Skip to content

Commit b63089c

Browse files
committed
[serve] Refactor prepare_http_options method
Signed-off-by: axreldable <aleksei.starikov.ax@gmail.com>
1 parent b4c6107 commit b63089c

File tree

4 files changed

+124
-32
lines changed

4 files changed

+124
-32
lines changed

python/ray/serve/api.py

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@
3939
)
4040
from ray.serve.config import (
4141
AutoscalingConfig,
42-
DeploymentMode,
4342
HTTPOptions,
4443
ProxyLocation,
4544
RequestRouterConfig,
4645
gRPCOptions,
46+
prepare_http_options,
4747
)
4848
from ray.serve.context import (
4949
ReplicaContext,
@@ -64,32 +64,6 @@
6464
logger = logging.getLogger(SERVE_LOGGER_NAME)
6565

6666

67-
def _prepare_http_options(
68-
proxy_location: Union[None, str, ProxyLocation],
69-
http_options: Union[None, dict, HTTPOptions],
70-
) -> HTTPOptions:
71-
if proxy_location is None:
72-
# default value of ProxyLocation (EveryNode) will be used
73-
# to set http_options.location if it wasn't set explicitly
74-
if http_options is None:
75-
http_options = HTTPOptions(location=DeploymentMode.EveryNode)
76-
return http_options
77-
elif isinstance(http_options, dict):
78-
result_http_options = HTTPOptions(**http_options)
79-
if "location" not in http_options:
80-
result_http_options.location = DeploymentMode.EveryNode
81-
return result_http_options
82-
else:
83-
return http_options
84-
else:
85-
if http_options is None:
86-
http_options = HTTPOptions()
87-
elif isinstance(http_options, dict):
88-
http_options = HTTPOptions(**http_options)
89-
http_options.location = ProxyLocation._to_deployment_mode(proxy_location)
90-
return http_options
91-
92-
9367
@PublicAPI(stability="stable")
9468
def start(
9569
proxy_location: Union[None, str, ProxyLocation] = None,
@@ -122,7 +96,7 @@ class See `gRPCOptions` for supported options.
12296
logging_config: logging config options for the serve component (
12397
controller & proxy).
12498
"""
125-
http_options = _prepare_http_options(proxy_location, http_options)
99+
http_options = prepare_http_options(proxy_location, http_options)
126100
_private_api.serve_start(
127101
http_options=http_options,
128102
grpc_options=grpc_options,

python/ray/serve/config.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,55 @@ class Config:
500500
arbitrary_types_allowed = True
501501

502502

503+
def prepare_http_options(
504+
proxy_location: Union[None, str, ProxyLocation],
505+
http_options: Union[None, dict, HTTPOptions],
506+
) -> HTTPOptions:
507+
"""Prepare `HTTPOptions` with desired location based on the proxy location given.
508+
509+
If `proxy_location` is provided `http_options.location` is determined by it.
510+
Alternatively, if `http_options.location` is specified explicitly by user,
511+
e.g. {"location": "NoServer"} or via HTTPOptions with or without location field
512+
e.g. HTTPOptions(location=DeploymentMode.EveryNode) or HTTPOptions(), then
513+
location provided by the user is used.
514+
515+
Args:
516+
proxy_location: provided ProxyLocation
517+
http_options: provided HTTPOptions
518+
519+
Returns:
520+
HTTPOptions: A new `HTTPOptions` instance with resolved location.
521+
522+
Note:
523+
Default ProxyLocation is `EveryNode`; default HTTPOptions() location is `HeadOnly`.
524+
525+
Raises:
526+
ValueError: If `http_options` is of an unexpected type.
527+
"""
528+
if http_options is None:
529+
location_set_explicitly = False
530+
http_options = HTTPOptions()
531+
elif isinstance(http_options, dict):
532+
location_set_explicitly = "location" in http_options
533+
http_options = HTTPOptions(**http_options)
534+
elif isinstance(http_options, HTTPOptions):
535+
# empty `HTTPOptions()` is considered as user specified the default location value `HeadOnly` explicitly
536+
location_set_explicitly = True
537+
http_options = HTTPOptions(**http_options.dict(exclude_unset=True))
538+
else:
539+
raise ValueError(
540+
f"Unexpected type for http_options: `{type(http_options).__name__}`"
541+
)
542+
543+
if proxy_location is None:
544+
if not location_set_explicitly:
545+
http_options.location = DeploymentMode.EveryNode
546+
else:
547+
http_options.location = ProxyLocation._to_deployment_mode(proxy_location)
548+
549+
return http_options
550+
551+
503552
@PublicAPI(stability="alpha")
504553
class gRPCOptions(BaseModel):
505554
"""gRPC options for the proxies. Supported fields:

python/ray/serve/scripts.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@
2727
SERVE_DEFAULT_APP_NAME,
2828
SERVE_NAMESPACE,
2929
)
30-
from ray.serve.api import _prepare_http_options
31-
from ray.serve.config import DeploymentMode, HTTPOptions, ProxyLocation, gRPCOptions
30+
from ray.serve.config import (
31+
DeploymentMode,
32+
HTTPOptions,
33+
ProxyLocation,
34+
gRPCOptions,
35+
prepare_http_options,
36+
)
3237
from ray.serve.deployment import Application, deployment_to_schema
3338
from ray.serve.schema import (
3439
LoggingConfig,
@@ -539,7 +544,7 @@ def run(
539544
http_options = HTTPOptions(**config.http_options.dict())
540545
grpc_options = gRPCOptions(**config.grpc_options.dict())
541546

542-
http_options = _prepare_http_options(proxy_location, http_options)
547+
http_options = prepare_http_options(proxy_location, http_options)
543548
client = _private_api.serve_start(
544549
http_options=http_options,
545550
grpc_options=grpc_options,

python/ray/serve/tests/unit/test_config.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
from ray import cloudpickle, serve
77
from ray._common.pydantic_compat import ValidationError
88
from ray._common.utils import import_attr
9-
from ray.serve._private.config import DeploymentConfig, ReplicaConfig, _proto_to_dict
9+
from ray.serve._private.config import (
10+
DeploymentConfig,
11+
ReplicaConfig,
12+
_proto_to_dict,
13+
)
1014
from ray.serve._private.constants import (
1115
DEFAULT_AUTOSCALING_POLICY_NAME,
1216
DEFAULT_GRPC_PORT,
@@ -21,6 +25,7 @@
2125
ProxyLocation,
2226
RequestRouterConfig,
2327
gRPCOptions,
28+
prepare_http_options,
2429
)
2530
from ray.serve.generated.serve_pb2 import (
2631
AutoscalingConfig as AutoscalingConfigProto,
@@ -649,6 +654,65 @@ def test_http_options():
649654
assert HTTPOptions(location=DeploymentMode.EveryNode).location == "EveryNode"
650655

651656

657+
def test_prepare_http_options():
658+
assert prepare_http_options(
659+
proxy_location=None,
660+
http_options=None,
661+
) == HTTPOptions(location=DeploymentMode.EveryNode)
662+
663+
assert prepare_http_options(
664+
proxy_location=None,
665+
http_options={},
666+
) == HTTPOptions(location=DeploymentMode.EveryNode)
667+
668+
assert (
669+
prepare_http_options(
670+
proxy_location=None,
671+
http_options=HTTPOptions(),
672+
)
673+
== HTTPOptions()
674+
)
675+
676+
assert prepare_http_options(
677+
proxy_location=None,
678+
http_options={"test": "test"},
679+
) == HTTPOptions(location=DeploymentMode.EveryNode)
680+
681+
assert prepare_http_options(
682+
proxy_location=None,
683+
http_options={"host": "0.0.0.0"},
684+
) == HTTPOptions(location=DeploymentMode.EveryNode, host="0.0.0.0")
685+
686+
assert prepare_http_options(
687+
proxy_location=None,
688+
http_options={"location": "NoServer"},
689+
) == HTTPOptions(location=DeploymentMode.NoServer)
690+
691+
assert prepare_http_options(
692+
proxy_location=ProxyLocation.Disabled,
693+
http_options=None,
694+
) == HTTPOptions(location=DeploymentMode.NoServer)
695+
696+
assert prepare_http_options(
697+
proxy_location=ProxyLocation.HeadOnly,
698+
http_options={"host": "0.0.0.0"},
699+
) == HTTPOptions(location=DeploymentMode.HeadOnly, host="0.0.0.0")
700+
701+
assert prepare_http_options(
702+
proxy_location=ProxyLocation.HeadOnly,
703+
http_options={"location": "NoServer"},
704+
) == HTTPOptions(location=DeploymentMode.HeadOnly)
705+
706+
with pytest.raises(ValueError, match="not a valid ProxyLocation"):
707+
prepare_http_options(proxy_location="wrong", http_options=None)
708+
709+
with pytest.raises(ValueError, match="not a valid enumeration"):
710+
prepare_http_options(proxy_location=None, http_options={"location": "123"})
711+
712+
with pytest.raises(ValueError, match="Unexpected type"):
713+
prepare_http_options(proxy_location=None, http_options="wrong")
714+
715+
652716
def test_with_proto():
653717
# Test roundtrip
654718
config = DeploymentConfig(num_replicas=100, max_ongoing_requests=16)

0 commit comments

Comments
 (0)