chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:17:40 +08:00
commit f1825c8ceb
10096 changed files with 2364182 additions and 0 deletions
@@ -0,0 +1,17 @@
applications:
- name: untyped_default
route_prefix: /untyped_default
import_path: ray.serve.tests.test_config_files.arg_builders.build_echo_app
- name: untyped_hello
route_prefix: /untyped_hello
import_path: ray.serve.tests.test_config_files.arg_builders.build_echo_app
args:
message: hello
- name: typed_default
route_prefix: /typed_default
import_path: ray.serve.tests.test_config_files.arg_builders.build_echo_app_typed
- name: typed_hello
route_prefix: /typed_hello
import_path: ray.serve.tests.test_config_files.arg_builders.build_echo_app_typed
args:
message: hello
@@ -0,0 +1,25 @@
from pydantic import BaseModel
from ray import serve
class TypedArgs(BaseModel):
message: str = "DEFAULT"
@serve.deployment(ray_actor_options={"num_cpus": 0})
class Echo:
def __init__(self, message: str):
print("Echo message:", message)
self._message = message
def __call__(self, *args):
return self._message
def build_echo_app(args):
return Echo.bind(args.get("message", "DEFAULT"))
def build_echo_app_typed(args: TypedArgs):
return Echo.bind(args.message)
@@ -0,0 +1,20 @@
applications:
- name: default
import_path: "dir.subdir.a.add_and_sub.serve_dag"
runtime_env:
# Keep these pinned remote URIs in sync with tests/common/remote_uris.py.
working_dir: "https://github.com/ray-project/test_dag/archive/203140040e4ab50b9d35b4773ec5c22615c034b3.zip"
deployments:
- name: "Router"
graceful_shutdown_timeout_s: 0.0001
- name: "Add"
graceful_shutdown_timeout_s: 0.0001
- name: "Subtract"
graceful_shutdown_timeout_s: 0.0001
ray_actor_options:
runtime_env:
# Keep these pinned remote URIs in sync with tests/common/remote_uris.py.
py_modules:
- "https://github.com/ray-project/test_module/archive/aa6f366f7daa78c98408c27d917a983caa9f888b.zip"
@@ -0,0 +1,25 @@
applications:
- name: "app1"
route_prefix: "/app1"
import_path: ray.serve.tests.test_config_files.pizza.serve_dag
deployments:
- name: Multiplier
user_config:
factor: 1
- name: Adder
user_config:
increment: 1
- name: "app2"
# Route prefixes should be unique across all apps!
route_prefix: "/app1"
import_path: ray.serve.tests.test_config_files.pizza.serve_dag
deployments:
- name: Multiplier
user_config:
factor: 2
- name: Adder
user_config:
increment: 3
@@ -0,0 +1,4 @@
applications:
- name: default
import_path: ray.serve.tests.test_config_files.test_dag.basic_dag.DagNode
runtime_env: {"working_dir": "s3://does_not_exist.zip"}
@@ -0,0 +1,4 @@
applications:
- name: default
route_prefix: /
import_path: ray.serve.tests.test_config_files.test_dag.basic_dag.DagNode
@@ -0,0 +1,7 @@
http_options:
host: 127.0.0.1
port: 8005
applications:
- name: default
import_path: ray.serve.tests.test_config_files.test_dag.basic_dag.DagNode
@@ -0,0 +1,3 @@
applications:
- name: "app1"
import_path: ray.serve.tests.test_config_files.test_dag.basic_dag.DagNode
@@ -0,0 +1,6 @@
http_options:
port: 8005
applications:
- name: "app1"
import_path: ray.serve.tests.test_config_files.test_dag.basic_dag.DagNode
@@ -0,0 +1,26 @@
import ray.cloudpickle as pickle
from ray import serve
class NonserializableException(Exception):
"""This exception cannot be serialized."""
def __reduce__(self):
raise RuntimeError("This exception cannot be serialized!")
# Confirm that NonserializableException cannot be serialized.
try:
pickle.dumps(NonserializableException())
except RuntimeError as e:
assert "This exception cannot be serialized!" in repr(e)
raise NonserializableException("custom exception info")
@serve.deployment
def f():
pass
app = f.bind()
@@ -0,0 +1,20 @@
"""Deployment that uses deployment actors but defines them only via config override.
The deployment has no deployment_actors in the @serve.deployment decorator;
they are added purely through the declarative config override.
"""
import ray
from ray import serve
@serve.deployment(ray_actor_options={"num_cpus": 0.1})
class ConfigOnlyDriver:
"""Uses get_deployment_actor; deployment_actors come from config only."""
def __call__(self):
counter = serve.get_deployment_actor("counter")
return str(ray.get(counter.get.remote()))
app = ConfigOnlyDriver.bind()
@@ -0,0 +1,13 @@
import asyncio
from ray import serve
@serve.deployment
class A:
async def __del__(self):
while True:
await asyncio.sleep(0.1)
app = A.bind()
@@ -0,0 +1,8 @@
grpc_options:
port: 9000
grpc_servicer_functions:
- ray.serve.generated.serve_pb2_grpc.add_UserDefinedServiceServicer_to_server
applications:
- name: app1
import_path: ray.serve.tests.test_config_files.grpc_deployment:g
@@ -0,0 +1,8 @@
grpc_options:
port: 9000
grpc_servicer_functions:
- ray.serve.generated.serve_pb2_grpc.add_FruitServiceServicer_to_server
applications:
- name: app1
import_path: ray.serve.tests.test_config_files.grpc_deployment:g2
@@ -0,0 +1,8 @@
grpc_options:
port: 9000
grpc_servicer_functions:
- ray.serve.generated.serve_pb2_grpc.add_UserDefinedServiceServicer_to_server
applications:
- name: app1
import_path: ray.serve.tests.test_config_files.grpc_deployment:multiplexed_g
@@ -0,0 +1,11 @@
applications:
- name: default
route_prefix: /
import_path: ray.serve.tests.test_config_files.config_only_deployment_actor:app
deployments:
- name: ConfigOnlyDriver
deployment_actors:
- name: counter
actor_class: ray.serve.tests.test_deployment_actors:SharedCounter
init_kwargs:
start: 88
@@ -0,0 +1,3 @@
applications:
- name: default
import_path: ray.serve.tests.test_config_files.fail.node
@@ -0,0 +1,3 @@
applications:
- name: default
import_path: ray.serve.tests.test_config_files.fail_2.node
@@ -0,0 +1,4 @@
applications:
- name: default
route_prefix: /
import_path: ray.serve.tests.test_config_files.test_dag.hello_serve:model
@@ -0,0 +1,8 @@
applications:
- name: app1
route_prefix: /a
import_path: ray.serve.tests.test_config_files.test_dag.basic_dag.DagNode
- name: app1
route_prefix: /b
import_path: ray.serve.tests.test_config_files.test_dag.basic_dag.DagNode
@@ -0,0 +1,8 @@
applications:
- name: app1
route_prefix: /alice
import_path: ray.serve.tests.test_config_files.test_dag.basic_dag.DagNode
- name: app2
route_prefix: /alice
import_path: ray.serve.tests.test_config_files.test_dag.basic_dag.DagNode
@@ -0,0 +1,10 @@
from ray import serve
@serve.deployment
class A:
def __init__(self):
_ = 1 / 0
node = A.bind()
@@ -0,0 +1,13 @@
import time
from ray import serve
@serve.deployment
class A:
def __init__(self):
time.sleep(5)
_ = 1 / 0
node = A.bind()
@@ -0,0 +1,16 @@
from fastapi import FastAPI
from ray import serve
app = FastAPI(docs_url="/my_docs")
@serve.deployment
@serve.ingress(app)
class FastAPIDeployment:
@app.get("/hello")
def incr(self):
return "Hello world!"
node = FastAPIDeployment.bind()
@@ -0,0 +1,29 @@
"""Test fixture: raises on first FLAKY_BUILD_FAIL_COUNT imports, then succeeds.
A counter file persists state across the fresh worker processes that
``build_serve_application``'s ``max_calls=1`` decorator spawns on each retry.
"""
import os
from ray import serve
_COUNTER_FILE = os.environ["FLAKY_BUILD_COUNTER_FILE"]
_FAIL_COUNT = int(os.environ.get("FLAKY_BUILD_FAIL_COUNT", "3"))
with open(_COUNTER_FILE, "r") as f:
_attempts = int(f.read().strip() or "0")
with open(_COUNTER_FILE, "w") as f:
f.write(str(_attempts + 1))
if _attempts < _FAIL_COUNT:
raise RuntimeError(f"flaky build failure on attempt {_attempts + 1}")
@serve.deployment
class FlakyApp:
def __call__(self):
return "ok"
node = FlakyApp.bind()
@@ -0,0 +1,21 @@
"""Flexible driver that works with or without deployment actors.
Used by declarative redeployment tests that need to transition from
no-deployment-actors to having them.
"""
import ray
from ray import serve
@serve.deployment(ray_actor_options={"num_cpus": 0.1})
class FlexDriver:
def __call__(self):
try:
actor = serve.get_deployment_actor("counter")
return str(ray.get(actor.get.remote()))
except Exception:
return "no_actor"
app = FlexDriver.bind()
@@ -0,0 +1,15 @@
import json
import os
from ray import serve
@serve.deployment
class GangApp:
def __call__(self, *args):
ctx = serve.context._get_internal_replica_context()
gc = ctx.gang_context
return json.dumps({"pid": os.getpid(), "gang_id": gc.gang_id if gc else None})
app = GangApp.bind()
@@ -0,0 +1,12 @@
applications:
- name: gang_app
route_prefix: /
import_path: ray.serve.tests.test_config_files.gang_scheduling:app
deployments:
- name: GangApp
num_replicas: 4
ray_actor_options:
num_cpus: 0.25
gang_scheduling_config:
gang_size: 2
gang_placement_strategy: PACK
@@ -0,0 +1,12 @@
applications:
- name: gang_app
route_prefix: /
import_path: ray.serve.tests.test_config_files.gang_scheduling:app
deployments:
- name: GangApp
num_replicas: 2
ray_actor_options:
num_cpus: 0.25
gang_scheduling_config:
gang_size: 2
gang_placement_strategy: PACK
@@ -0,0 +1,12 @@
applications:
- name: gang_app
route_prefix: /
import_path: ray.serve.tests.test_config_files.gang_scheduling:app
deployments:
- name: GangApp
num_replicas: 4
ray_actor_options:
num_cpus: 0.25
gang_scheduling_config:
gang_size: 2
gang_placement_strategy: PACK
@@ -0,0 +1,29 @@
import os
import ray
from ray import serve
from ray.serve.handle import DeploymentHandle
@serve.deployment
class A:
def __init__(self, b: DeploymentHandle):
self.b = b
self.signal = ray.get_actor("signal_A", namespace="default_test_namespace")
async def __call__(self):
await self.signal.wait.remote()
return os.getpid()
@serve.deployment
class B:
def __init__(self):
self.signal = ray.get_actor("signal_B", namespace="default_test_namespace")
async def __call__(self):
await self.signal.wait.remote()
return os.getpid()
app = A.bind(B.bind())
@@ -0,0 +1,15 @@
import os
import ray
from ray import serve
@serve.deployment
class A:
async def __call__(self):
signal = ray.get_actor("signal123")
await signal.wait.remote()
return os.getpid()
app = A.bind()
@@ -0,0 +1,125 @@
from typing import Dict
# Users need to include their custom message type which will be embedded in the request.
from ray import serve
from ray.serve.generated import serve_pb2
from ray.serve.handle import DeploymentHandle
@serve.deployment
class GrpcDeployment:
def __call__(self, user_message):
greeting = f"Hello {user_message.name} from {user_message.foo}"
num_x2 = user_message.num * 2
user_response = serve_pb2.UserDefinedResponse(
greeting=greeting,
num_x2=num_x2,
)
return user_response
def Method1(self, user_message):
greeting = f"Hello {user_message.name} from method1"
num_x2 = user_message.num * 3
user_response = serve_pb2.UserDefinedResponse(
greeting=greeting,
num_x2=num_x2,
)
return user_response
def Streaming(self, user_message):
for i in range(10):
greeting = f"{i}: Hello {user_message.name} from {user_message.foo}"
num_x2 = user_message.num * 2 + i
user_response = serve_pb2.UserDefinedResponse(
greeting=greeting,
num_x2=num_x2,
)
yield user_response
g = GrpcDeployment.options(name="grpc-deployment").bind()
# NOTE: model multiplexing is kept on a separate deployment (not the shared `g`)
# because it is not supported on the ingress deployment when direct ingress /
# HAProxy is enabled (the multiplexed model ID is not propagated to the replica).
# Tests that exercise it must be skipped under those modes.
@serve.deployment
class MultiplexedGrpcDeployment:
def __call__(self, user_message):
greeting = f"Hello {user_message.name} from {user_message.foo}"
return serve_pb2.UserDefinedResponse(greeting=greeting)
@serve.multiplexed(max_num_models_per_replica=1)
async def get_model(self, model_id: str) -> str:
return f"loading model: {model_id}"
async def Method2(self, user_message):
model_id = serve.get_multiplexed_model_id()
model = await self.get_model(model_id)
user_response = serve_pb2.UserDefinedResponse(
greeting=f"Method2 called model, {model}",
)
return user_response
multiplexed_g = MultiplexedGrpcDeployment.options(name="grpc-deployment").bind()
@serve.deployment(ray_actor_options={"num_cpus": 0})
class FruitMarket:
def __init__(
self,
_orange_stand: DeploymentHandle,
_apple_stand: DeploymentHandle,
):
self.directory = {
"ORANGE": _orange_stand,
"APPLE": _apple_stand,
}
async def FruitStand(self, fruit_amounts_proto):
fruit_amounts = {}
if fruit_amounts_proto.orange:
fruit_amounts["ORANGE"] = fruit_amounts_proto.orange
if fruit_amounts_proto.apple:
fruit_amounts["APPLE"] = fruit_amounts_proto.apple
if fruit_amounts_proto.banana:
fruit_amounts["BANANA"] = fruit_amounts_proto.banana
costs = await self.check_price(fruit_amounts)
return serve_pb2.FruitCosts(costs=costs)
async def check_price(self, inputs: Dict[str, int]) -> float:
costs = 0
for fruit, amount in inputs.items():
if fruit not in self.directory:
return
fruit_stand = self.directory[fruit]
costs += await fruit_stand.remote(int(amount))
return costs
@serve.deployment(ray_actor_options={"num_cpus": 0})
class OrangeStand:
def __init__(self):
self.price = 2.0
def __call__(self, num_oranges: int):
return num_oranges * self.price
@serve.deployment(ray_actor_options={"num_cpus": 0})
class AppleStand:
def __init__(self):
self.price = 3.0
def __call__(self, num_oranges: int):
return num_oranges * self.price
orange_stand = OrangeStand.bind()
apple_stand = AppleStand.bind()
g2 = FruitMarket.options(name="grpc-deployment-model-composition").bind(
orange_stand, apple_stand
)
@@ -0,0 +1,13 @@
import ray
from ray import serve
signal = ray.get_actor("signal123")
ray.get(signal.wait.remote())
@serve.deployment(ray_actor_options={"num_cpus": 0.1})
def f():
return "hello world"
app = f.bind()
@@ -0,0 +1,14 @@
import time
from ray import serve
@serve.deployment
def sleep(request):
sleep_s = float(request.query_params.get("sleep_s", 0))
print(f"sleep_s: {sleep_s}")
time.sleep(sleep_s)
return "Task Succeeded!"
sleep_node = sleep.bind()
@@ -0,0 +1,7 @@
http_options:
request_timeout_s: 0.1
applications:
- name: "app1"
import_path: ray.serve.tests.test_config_files.http_option_app_sleeps.sleep_node
route_prefix: /app1
@@ -0,0 +1,11 @@
from ray import serve
_ = 1 / 0
@serve.deployment(ray_actor_options={"num_cpus": 0.1})
def f(*args):
return "hello world"
app = f.bind()
@@ -0,0 +1,62 @@
import logging
import ray
from ray import serve
from ray.exceptions import RayActorError
from ray.serve.context import _get_global_client
logger = logging.getLogger("ray.serve")
@serve.deployment
class Model:
def __call__(self):
logger.debug("this_is_debug_info")
logger.info("this_is_access_log", extra={"serve_access_log": True})
log_file = logger.handlers[1].target.baseFilename
return {
"log_file": log_file,
"replica": serve.get_replica_context().replica_id.to_full_id_str(),
"log_level": logger.level,
"num_handlers": len(logger.handlers),
}
@serve.deployment
class Router:
def __init__(self, handle):
self.handle = handle
async def __call__(self):
logger.debug("this_is_debug_info_from_router")
log_info = await self.handle.remote()
if len(logger.handlers) == 2:
log_info["router_log_file"] = logger.handlers[1].target.baseFilename
else:
log_info["router_log_file"] = None
log_info["router_log_level"] = logger.level
try:
# Add controller log file path
client = _get_global_client()
_, log_file_path = ray.get(client._controller._get_logging_config.remote())
except RayActorError:
log_file_path = None
log_info["controller_log_file"] = log_file_path
return log_info
model = Router.bind(Model.bind())
@serve.deployment(logging_config={"log_level": "DEBUG"})
class ModelWithConfig:
def __call__(self):
logger.debug("this_is_debug_info")
log_file = logger.handlers[1].target.baseFilename
return {"log_file": log_file}
model2 = ModelWithConfig.bind()
@@ -0,0 +1,10 @@
from ray import serve
@serve.deployment
class D:
def __call__(self, *args):
return "hi"
app = D.bind()
@@ -0,0 +1,15 @@
applications:
- name: valid
route_prefix: /valid
import_path: ray.serve.tests.test_config_files.max_replicas_per_node.app
deployments:
- name: D
max_replicas_per_node: 2
- name: invalid
route_prefix: /invalid
import_path: ray.serve.tests.test_config_files.max_replicas_per_node.app
deployments:
- name: D
# Non-positive max_replicas_per_node.
max_replicas_per_node: 0
@@ -0,0 +1,4 @@
applications:
- name: default
import_path: "basic_dag.DagNode"
route_prefix: /
@@ -0,0 +1,28 @@
from fastapi import FastAPI
from ray import serve
from ray.serve.handle import DeploymentHandle
app1 = FastAPI()
app2 = FastAPI()
@serve.deployment
@serve.ingress(app2)
class SubModel:
def add(self, a: int):
return a + 1
@serve.deployment
@serve.ingress(app1)
class Model:
def __init__(self, submodel: DeploymentHandle):
self.submodel = submodel
@app1.get("/{a}")
async def func(self, a: int):
return await self.submodel.add.remote(a)
invalid_model = Model.bind(SubModel.bind())
@@ -0,0 +1,78 @@
import asyncio
import os
import time
from ray import serve
@serve.deployment
class f:
def __init__(self, async_wait: bool = False):
# whether to use wait() (busy spin) or async_wait() (busy spin
# while yielding event loop)
self._async = async_wait
# to be updated through reconfigure()
self.name = "default_name"
# used to block calls to __call__()
self.ready = True
# used to check how many times __call__() has been called
self.counter = 0
# used to block calls to health_check()
self.health_check_ready = True
# used to check how many times health_check() has been called
self.health_check_counter = 0
async def get_counter(self, health_check=False) -> int:
if health_check:
return self.health_check_counter
else:
return self.counter
def send(self, clear=False, health_check=False):
if health_check:
self.health_check_ready = not clear
else:
self.ready = not clear
def wait(self, _health_check=False):
if _health_check:
while not self.health_check_ready:
time.sleep(0.1)
else:
while not self.ready:
time.sleep(0.1)
async def async_wait(self, _health_check=False):
if _health_check:
while not self.health_check_ready:
await asyncio.sleep(0.1)
else:
while not self.ready:
await asyncio.sleep(0.1)
def reconfigure(self, config: dict):
self.name = config.get("name", "default_name")
async def __call__(self):
self.counter += 1
if self._async:
await self.async_wait()
else:
self.wait()
return os.getpid(), self.name
async def check_health(self):
self.health_check_counter += 1
if self._async:
await self.async_wait(_health_check=True)
else:
self.wait(_health_check=True)
node = f.bind()
dup_node = f.bind()
async_node = f.bind(async_wait=True)
@@ -0,0 +1,79 @@
from enum import Enum
from typing import Dict, List
import starlette.requests
from ray import serve
from ray.serve.handle import DeploymentHandle
class Operation(str, Enum):
ADDITION = "ADD"
MULTIPLICATION = "MUL"
@serve.deployment(ray_actor_options={"num_cpus": 0.15})
class Router:
def __init__(self, multiplier: DeploymentHandle, adder: DeploymentHandle):
self.adder = adder
self.multiplier = multiplier
async def route(self, op: Operation, input: int) -> str:
if op == Operation.ADDITION:
amount = await self.adder.add.remote(input)
elif op == Operation.MULTIPLICATION:
amount = await self.multiplier.multiply.remote(input)
return f"{amount} pizzas please!"
async def __call__(self, request: starlette.requests.Request) -> str:
op, input = await request.json()
return await self.route(op, input)
@serve.deployment(
user_config={
"factor": 3,
},
ray_actor_options={"num_cpus": 0.15},
)
class Multiplier:
def __init__(self, factor: int):
self.factor = factor
def reconfigure(self, config: Dict):
self.factor = config.get("factor", -1)
def multiply(self, input_factor: int) -> int:
return input_factor * self.factor
@serve.deployment(
user_config={
"increment": 2,
},
ray_actor_options={"num_cpus": 0.15},
)
class Adder:
def __init__(self, increment: int):
self.increment = increment
def reconfigure(self, config: Dict):
self.increment = config.get("increment", -1)
def add(self, input: int) -> int:
return input + self.increment
async def json_resolver(request: starlette.requests.Request) -> List:
return await request.json()
# Overwritten by user_config
ORIGINAL_INCREMENT = 1
ORIGINAL_FACTOR = 1
multiplier = Multiplier.bind(ORIGINAL_FACTOR)
adder = Adder.bind(ORIGINAL_INCREMENT)
serve_dag = Router.bind(multiplier, adder)
@@ -0,0 +1,20 @@
applications:
- name: default
route_prefix: /
import_path: ray.serve.tests.test_config_files.test_dag.conditional_dag.serve_dag
deployments:
- name: Router
graceful_shutdown_timeout_s: 0.0001
- name: Multiplier
graceful_shutdown_timeout_s: 0.0001
user_config:
factor: 1
- name: Adder
graceful_shutdown_timeout_s: 0.0001
ray_actor_options:
runtime_env:
env_vars:
override_increment: '1'
@@ -0,0 +1,16 @@
applications:
- name: "app1"
route_prefix: "/app1"
import_path: ray.serve.tests.test_config_files.world.DagNode
- name: "app2"
route_prefix: "/app2"
import_path: ray.serve.tests.test_config_files.pizza.serve_dag
deployments:
- name: Multiplier
user_config:
factor: 10
- name: Adder
user_config:
increment: 10
@@ -0,0 +1,12 @@
import ray
from ray import serve
ray.init(address="auto")
@serve.deployment
def f():
return "foobar"
app = f.bind()
@@ -0,0 +1,10 @@
from ray import serve
@serve.deployment
class D:
def __call__(self, *args):
return "hi"
app = D.bind()
@@ -0,0 +1,27 @@
applications:
- name: valid
route_prefix: /valid
import_path: ray.serve.tests.test_config_files.replica_placement_groups.app
deployments:
- name: D
placement_group_bundles:
- {"CPU": 1}
placement_group_strategy: STRICT_PACK
- name: invalid_bundles
route_prefix: /invalid_bundles
import_path: ray.serve.tests.test_config_files.replica_placement_groups.app
deployments:
- name: D
# Insufficient resources for the replica actor.
placement_group_bundles:
- {"CPU": 0.1}
- name: invalid_strategy
route_prefix: /invalid_strategy
import_path: ray.serve.tests.test_config_files.replica_placement_groups.app
deployments:
- name: D
placement_group_bundles:
- {"CPU": 1}
placement_group_strategy: FAKE_NEWS
@@ -0,0 +1,15 @@
from ray import serve
@serve.deployment
class TestDeployment:
def __init__(self):
import pymysql
from sqlalchemy import create_engine
pymysql.install_as_MySQLdb()
create_engine("mysql://some_wrong_url:3306").connect()
app = TestDeployment.bind()
@@ -0,0 +1,11 @@
applications:
- name: default
import_path: ray.serve.tests.test_config_files.sqlalchemy.app
deployments:
- name: TestDeployment
num_replicas: 1
ray_actor_options:
runtime_env:
pip:
- PyMySQL
- sqlalchemy==1.3.19
@@ -0,0 +1 @@
x = (1 + 2
@@ -0,0 +1,3 @@
applications:
- name: default
import_path: ray.serve.tests.test_config_files.syntax_error.app
@@ -0,0 +1,28 @@
from ray import serve
from ray.serve.handle import DeploymentHandle
@serve.deployment(
ray_actor_options={
"num_cpus": 0.1,
}
)
def f(*args):
return "wonderful world"
@serve.deployment(
ray_actor_options={
"num_cpus": 0.1,
}
)
class BasicDriver:
def __init__(self, h: DeploymentHandle):
self._h = h
async def __call__(self):
return await self._h.remote()
FNode = f.bind()
DagNode = BasicDriver.bind(FNode)
@@ -0,0 +1,97 @@
import os
from enum import Enum
from typing import Dict
import starlette.requests
from ray import serve
from ray.serve.handle import DeploymentHandle
class Operation(str, Enum):
ADDITION = "ADD"
MULTIPLICATION = "MUL"
@serve.deployment(
ray_actor_options={
"num_cpus": 0.1,
}
)
class Router:
def __init__(self, multiplier: DeploymentHandle, adder: DeploymentHandle):
self.adder = adder
self.multiplier = multiplier
async def route(self, op: Operation, input: int) -> int:
if op == Operation.ADDITION:
amount = await self.adder.add.remote(input)
elif op == Operation.MULTIPLICATION:
amount = await self.multiplier.multiply.remote(input)
return f"{amount} pizzas please!"
async def __call__(self, request: starlette.requests.Request) -> str:
op, input = await request.json()
return await self.route(op, input)
@serve.deployment(
user_config={
"factor": 3,
},
ray_actor_options={
"num_cpus": 0.1,
"runtime_env": {
"env_vars": {
"override_factor": "-2",
}
},
},
)
class Multiplier:
def __init__(self, factor: int):
self.factor = factor
def reconfigure(self, config: Dict):
self.factor = config.get("factor", -1)
def multiply(self, input_factor: int) -> int:
if os.getenv("override_factor") is not None:
return input_factor * int(os.getenv("override_factor"))
return input_factor * self.factor
@serve.deployment(
user_config={
"increment": 2,
},
ray_actor_options={
"num_cpus": 0.1,
"runtime_env": {
"env_vars": {
"override_increment": "-2",
}
},
},
)
class Adder:
def __init__(self, increment: int):
self.increment = increment
def reconfigure(self, config: Dict):
self.increment = config.get("increment", -1)
def add(self, input: int) -> int:
if os.getenv("override_increment") is not None:
return input + int(os.getenv("override_increment"))
return input + self.increment
# Overwritten by user_config
ORIGINAL_INCREMENT = 1
ORIGINAL_FACTOR = 1
multiplier = Multiplier.bind(ORIGINAL_FACTOR)
adder = Adder.bind(ORIGINAL_INCREMENT)
serve_dag = Router.bind(multiplier, adder)
@@ -0,0 +1,65 @@
from enum import Enum
import starlette.requests
from ray import serve
from ray.serve.handle import DeploymentHandle
class Operation(str, Enum):
ADD = "ADD"
SUBTRACT = "SUB"
@serve.deployment(
ray_actor_options={
"num_cpus": 0.1,
}
)
class Add:
# Requires the test_dag repo as a py_module:
# https://github.com/ray-project/test_dag
def add(self, input: int) -> int:
from dir2.library import add_one
return add_one(input)
@serve.deployment(
ray_actor_options={
"num_cpus": 0.1,
}
)
class Subtract:
# Requires the test_module repo as a py_module:
# https://github.com/ray-project/test_module
def subtract(self, input: int) -> int:
from test_module.test import one
return input - one() # Returns input - 2
@serve.deployment(
ray_actor_options={
"num_cpus": 0.1,
}
)
class Router:
def __init__(self, adder: DeploymentHandle, subtractor: DeploymentHandle):
self.adder = adder
self.subtractor = subtractor
async def __call__(self, request: starlette.requests.Request) -> int:
op, input = await request.json()
if op == Operation.ADD:
return await self.adder.add.remote(input)
elif op == Operation.SUBTRACT:
return await self.subtractor.subtract.remote(input)
adder = Add.bind()
subtractor = Subtract.bind()
serve_dag = Router.bind(adder, subtractor)
@@ -0,0 +1,2 @@
def add_one(inp):
return inp + 1
@@ -0,0 +1,13 @@
from starlette.requests import Request
from ray import serve
from ray.serve.tests.test_config_files.test_dag.utils.test import hello
@serve.deployment
class HelloModel:
async def __call__(self, starlette_request: Request) -> None:
return hello()
model = HelloModel.bind()
@@ -0,0 +1,2 @@
def hello():
return "hello_from_utils"
@@ -0,0 +1,24 @@
applications:
- name: "app1"
route_prefix: "/app1"
import_path: ray.serve.tests.test_config_files.pizza.serve_dag
deployments:
- name: Multiplier
user_config:
factor: 1
- name: Adder
user_config:
increment: 1
- name: "app2"
route_prefix: "/app2"
import_path: ray.serve.tests.test_config_files.pizza.serve_dag
deployments:
- name: Multiplier
user_config:
factor: 2
- name: Adder
user_config:
increment: 3
@@ -0,0 +1,9 @@
from ray import serve
@serve.deployment
def f():
return "hi"
app = f.bind()
@@ -0,0 +1,6 @@
applications:
- name: app1
route_prefix: /
import_path: use_current_working_directory:app
deployments:
- name: f
@@ -0,0 +1,16 @@
applications:
- name: app1
route_prefix: /
import_path: ray.serve.tests.test_config_files.use_custom_autoscaling_policy:app
deployments:
- name: CustomAutoscalingPolicy
num_replicas: auto
ray_actor_options:
num_cpus: 0.0
autoscaling_config:
min_replicas: 1
max_replicas: 2
upscale_delay_s: 1
downscale_delay_s: 2
policy:
policy_function: ray.serve.tests.test_config_files.use_custom_autoscaling_policy.custom_autoscaling_policy
@@ -0,0 +1,16 @@
from ray import serve
from ray.serve.config import AutoscalingContext
def custom_autoscaling_policy(ctx: AutoscalingContext):
print("custom_autoscaling_policy")
return 2, {}
@serve.deployment
class CustomAutoscalingPolicy:
def __call__(self):
return "hello_from_custom_autoscaling_policy"
app = CustomAutoscalingPolicy.bind()
@@ -0,0 +1,47 @@
import random
from typing import (
List,
Optional,
)
from ray import serve
from ray.serve.context import _get_internal_replica_context
from ray.serve.request_router import (
PendingRequest,
ReplicaID,
ReplicaResult,
RequestRouter,
RunningReplica,
)
class UniformRequestRouter(RequestRouter):
async def choose_replicas(
self,
candidate_replicas: List[RunningReplica],
pending_request: Optional[PendingRequest] = None,
) -> List[List[RunningReplica]]:
print("UniformRequestRouter routing request")
index = random.randint(0, len(candidate_replicas) - 1)
return [[candidate_replicas[index]]]
def on_request_routed(
self,
pending_request: PendingRequest,
replica_id: ReplicaID,
result: ReplicaResult,
):
print("on_request_routed callback is called!!")
@serve.deployment
class UniformRequestRouterApp:
def __init__(self):
context = _get_internal_replica_context()
self.replica_id: ReplicaID = context.replica_id
async def __call__(self):
return "hello_from_custom_request_router"
app = UniformRequestRouterApp.bind()
@@ -0,0 +1,14 @@
applications:
- name: app1
route_prefix: /
import_path: ray.serve.tests.test_config_files.use_custom_request_router:app
deployments:
- name: UniformRequestRouterApp
num_replicas: 2
ray_actor_options:
num_cpus: 0.0
request_router_config:
request_router_class: ray.serve.tests.test_config_files.use_custom_request_router.UniformRequestRouter
request_router_kwargs: {}
request_routing_stats_period_s: 10
request_routing_stats_timeout_s: 30
@@ -0,0 +1,20 @@
from ray import serve
from ray.serve.handle import DeploymentHandle
@serve.deployment(ray_actor_options={"num_cpus": 0.1})
def f(*args):
return "wonderful world"
@serve.deployment(ray_actor_options={"num_cpus": 0.1})
class BasicDriver:
def __init__(self, h: DeploymentHandle):
self._h = h
async def __call__(self):
return await self._h.remote()
FNode = f.bind()
DagNode = BasicDriver.bind(FNode)