Skip to content

Commit 3d44bf7

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

File tree

4 files changed

+132
-33
lines changed

4 files changed

+132
-33
lines changed

python/ray/serve/_private/config.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,14 @@
2828
MAX_REPLICAS_PER_NODE_MAX_VALUE,
2929
)
3030
from ray.serve._private.utils import DEFAULT, DeploymentOptionUpdateType
31-
from ray.serve.config import AggregationFunction, AutoscalingConfig, RequestRouterConfig
31+
from ray.serve.config import (
32+
AggregationFunction,
33+
AutoscalingConfig,
34+
DeploymentMode,
35+
HTTPOptions,
36+
ProxyLocation,
37+
RequestRouterConfig,
38+
)
3239
from ray.serve.generated.serve_pb2 import (
3340
AutoscalingConfig as AutoscalingConfigProto,
3441
DeploymentConfig as DeploymentConfigProto,
@@ -789,3 +796,52 @@ def to_proto(self):
789796

790797
def to_proto_bytes(self):
791798
return self.to_proto().SerializeToString()
799+
800+
801+
def prepare_http_options(
802+
proxy_location: Union[None, str, ProxyLocation],
803+
http_options: Union[None, dict, HTTPOptions],
804+
) -> HTTPOptions:
805+
"""Prepare `HTTPOptions` with desired location based on the proxy location given.
806+
807+
If `proxy_location` is provided `http_options.location` is determined by it.
808+
Alternatively, if `http_options.location` is specified explicitly by user,
809+
e.g. {"location": "NoServer"} or via HTTPOptions with or without location field
810+
e.g. HTTPOptions(location=DeploymentMode.EveryNode) or HTTPOptions(), then
811+
location provided by the user is used.
812+
813+
Args:
814+
proxy_location: provided ProxyLocation
815+
http_options: provided HTTPOptions
816+
817+
Returns:
818+
HTTPOptions: A new `HTTPOptions` instance with resolved location.
819+
820+
Note:
821+
Default ProxyLocation is `EveryNode`; default HTTPOptions() location is `HeadOnly`.
822+
823+
Raises:
824+
ValueError: If `http_options` is of an unexpected type.
825+
"""
826+
if http_options is None:
827+
location_set_explicitly = False
828+
http_options = HTTPOptions()
829+
elif isinstance(http_options, dict):
830+
location_set_explicitly = "location" in http_options
831+
http_options = HTTPOptions(**http_options)
832+
elif isinstance(http_options, HTTPOptions):
833+
# empty `HTTPOptions()` is considered as user specified the default location value `HeadOnly` explicitly
834+
location_set_explicitly = True
835+
http_options = HTTPOptions(**http_options.dict(exclude_unset=True))
836+
else:
837+
raise ValueError(
838+
f"Unexpected type for http_options: `{type(http_options).__name__}`"
839+
)
840+
841+
if proxy_location is None:
842+
if not location_set_explicitly:
843+
http_options.location = DeploymentMode.EveryNode
844+
else:
845+
http_options.location = ProxyLocation._to_deployment_mode(proxy_location)
846+
847+
return http_options

python/ray/serve/api.py

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
DeploymentConfig,
1717
ReplicaConfig,
1818
handle_num_replicas_auto,
19+
prepare_http_options,
1920
)
2021
from ray.serve._private.constants import (
2122
RAY_SERVE_FORCE_LOCAL_TESTING_MODE,
@@ -39,7 +40,6 @@
3940
)
4041
from ray.serve.config import (
4142
AutoscalingConfig,
42-
DeploymentMode,
4343
HTTPOptions,
4444
ProxyLocation,
4545
RequestRouterConfig,
@@ -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/scripts.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,20 @@
2020
from ray.dashboard.modules.serve.sdk import ServeSubmissionClient
2121
from ray.serve._private import api as _private_api
2222
from ray.serve._private.build_app import BuiltApplication, build_app
23+
from ray.serve._private.config import prepare_http_options
2324
from ray.serve._private.constants import (
2425
DEFAULT_GRPC_PORT,
2526
DEFAULT_HTTP_HOST,
2627
DEFAULT_HTTP_PORT,
2728
SERVE_DEFAULT_APP_NAME,
2829
SERVE_NAMESPACE,
2930
)
30-
from ray.serve.api import _prepare_http_options
31-
from ray.serve.config import DeploymentMode, HTTPOptions, ProxyLocation, gRPCOptions
31+
from ray.serve.config import (
32+
DeploymentMode,
33+
HTTPOptions,
34+
ProxyLocation,
35+
gRPCOptions,
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,12 @@
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+
prepare_http_options,
14+
)
1015
from ray.serve._private.constants import (
1116
DEFAULT_AUTOSCALING_POLICY_NAME,
1217
DEFAULT_GRPC_PORT,
@@ -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)