315 lines
10 KiB
Python
315 lines
10 KiB
Python
import os
|
|
import warnings
|
|
from typing import Callable, List, Optional, Type, TypeVar
|
|
|
|
|
|
def str_to_list(s: str) -> List[str]:
|
|
"""Return a list from a comma-separated string.
|
|
|
|
Trims whitespace and skips empty entries.
|
|
"""
|
|
return [part for part in (part.strip() for part in s.split(",")) if part]
|
|
|
|
|
|
def parse_latency_buckets(bucket_str: str, default_buckets: List[float]) -> List[float]:
|
|
"""Parse a comma-separated string of latency bucket values.
|
|
|
|
Args:
|
|
bucket_str: A comma-separated string of positive numbers in ascending order.
|
|
default_buckets: Default bucket values to use if bucket_str is empty.
|
|
|
|
Returns:
|
|
A list of parsed float values.
|
|
|
|
Raises:
|
|
ValueError: If the format is invalid or values don't meet requirements.
|
|
"""
|
|
if bucket_str.strip() == "":
|
|
return default_buckets
|
|
try:
|
|
# Convert string to list of floats
|
|
buckets = [float(x.strip()) for x in bucket_str.split(",")]
|
|
|
|
if not buckets:
|
|
raise ValueError("Empty bucket list")
|
|
if any(x <= 0 for x in buckets):
|
|
raise ValueError("Bucket values must be positive")
|
|
if sorted(set(buckets)) != buckets:
|
|
raise ValueError("Bucket values must be in strictly ascending order")
|
|
|
|
return buckets
|
|
except Exception as e:
|
|
raise ValueError(
|
|
f"Invalid format for `{bucket_str}`. "
|
|
f"Expected comma-separated positive numbers in ascending order. Error: {str(e)}"
|
|
) from e
|
|
|
|
|
|
T = TypeVar("T")
|
|
|
|
# todo: remove for the '3.0.0' release.
|
|
_wrong_names_white_list = {
|
|
"REQUEST_LATENCY_BUCKETS_MS",
|
|
"MODEL_LOAD_LATENCY_BUCKETS_MS",
|
|
"MAX_CACHED_HANDLES",
|
|
"SERVE_REQUEST_PROCESSING_TIMEOUT_S",
|
|
}
|
|
|
|
|
|
def _validate_name(name: str) -> None:
|
|
"""Validate Ray Serve environment variable name."""
|
|
required_prefix = "RAY_SERVE_"
|
|
|
|
if not name.startswith(required_prefix):
|
|
if name in _wrong_names_white_list:
|
|
return
|
|
|
|
raise ValueError(
|
|
f"Got unexpected environment variable name `{name}`! "
|
|
f"Ray Serve environment variables require prefix `{required_prefix}`. "
|
|
)
|
|
|
|
|
|
def _get_env_value(
|
|
name: str,
|
|
default: Optional[T],
|
|
value_type: Type[T],
|
|
validation_func: Optional[Callable[[T], bool]] = None,
|
|
expected_value_description: Optional[str] = None,
|
|
) -> Optional[T]:
|
|
"""Get environment variable with type conversion and validation.
|
|
|
|
This function retrieves an environment variable, converts it to the specified type,
|
|
and optionally validates the converted value.
|
|
|
|
Args:
|
|
name: The name of the environment variable.
|
|
default: Default value to use if the environment variable is not set.
|
|
If None, the function will return None without validation.
|
|
value_type: Type to convert the environment variable value to (e.g., int, float, str).
|
|
validation_func: Optional function that takes the converted value and returns
|
|
a boolean indicating whether the value is valid.
|
|
expected_value_description: Description of the expected value characteristics
|
|
(e.g., "positive", "non-negative") used in error messages.
|
|
Optional, expected only if validation_func is provided.
|
|
|
|
Returns:
|
|
The environment variable value converted to the specified type and validated,
|
|
or the default value if the environment variable is not set.
|
|
|
|
Raises:
|
|
ValueError: If the environment variable value cannot be converted to the specified
|
|
type, or if it fails the optional validation check. Also, if name validation fails.
|
|
"""
|
|
_validate_name(name)
|
|
|
|
explicitly_defined_value = os.environ.get(name)
|
|
if explicitly_defined_value is None:
|
|
if default is None:
|
|
return None
|
|
else:
|
|
raw = default
|
|
else:
|
|
_deprecation_warning(name)
|
|
raw = explicitly_defined_value
|
|
|
|
try:
|
|
value = value_type(raw)
|
|
except ValueError as e:
|
|
raise ValueError(
|
|
f"Environment variable `{name}` value `{raw}` cannot be converted to `{value_type.__name__}`!"
|
|
) from e
|
|
|
|
if validation_func and not validation_func(value):
|
|
raise ValueError(
|
|
f"Got unexpected value `{value}` for `{name}` environment variable! "
|
|
f"Expected {expected_value_description} `{value_type.__name__}`."
|
|
)
|
|
|
|
return value
|
|
|
|
|
|
def get_env_int(name: str, default: Optional[int]) -> Optional[int]:
|
|
"""Get environment variable as an integer.
|
|
|
|
Args:
|
|
name: The name of the environment variable.
|
|
default: Default value to use if the environment variable is not set.
|
|
|
|
Returns:
|
|
The environment variable value as an integer.
|
|
|
|
Raises:
|
|
ValueError: If the value cannot be converted to an integer.
|
|
"""
|
|
return _get_env_value(name, default, int)
|
|
|
|
|
|
def get_env_int_positive(name: str, default: Optional[int]) -> Optional[int]:
|
|
"""Get environment variable as a positive integer.
|
|
|
|
Args:
|
|
name: The name of the environment variable.
|
|
default: Default value to use if the environment variable is not set.
|
|
|
|
Returns:
|
|
The environment variable value as a positive integer.
|
|
|
|
Raises:
|
|
ValueError: If the value cannot be converted to an integer or is not positive.
|
|
"""
|
|
return _get_env_value(name, default, int, lambda x: x > 0, "positive")
|
|
|
|
|
|
def get_env_int_non_negative(name: str, default: Optional[int]) -> Optional[int]:
|
|
"""Get environment variable as a non-negative integer.
|
|
|
|
Args:
|
|
name: The name of the environment variable.
|
|
default: Default value to use if the environment variable is not set.
|
|
|
|
Returns:
|
|
The environment variable value as a non-negative integer.
|
|
|
|
Raises:
|
|
ValueError: If the value cannot be converted to an integer or is negative.
|
|
"""
|
|
return _get_env_value(name, default, int, lambda x: x >= 0, "non negative")
|
|
|
|
|
|
def get_env_float(name: str, default: Optional[float]) -> Optional[float]:
|
|
"""Get environment variable as a float.
|
|
|
|
Args:
|
|
name: The name of the environment variable.
|
|
default: Default value to use if the environment variable is not set.
|
|
|
|
Returns:
|
|
The environment variable value as a float.
|
|
|
|
Raises:
|
|
ValueError: If the value cannot be converted to a float.
|
|
"""
|
|
return _get_env_value(name, default, float)
|
|
|
|
|
|
def get_env_float_positive(name: str, default: Optional[float]) -> Optional[float]:
|
|
"""Get environment variable as a positive float.
|
|
|
|
Args:
|
|
name: The name of the environment variable.
|
|
default: Default value to use if the environment variable is not set.
|
|
|
|
Returns:
|
|
The environment variable value as a positive float.
|
|
|
|
Raises:
|
|
ValueError: If the value cannot be converted to a float or is not positive.
|
|
"""
|
|
return _get_env_value(name, default, float, lambda x: x > 0, "positive")
|
|
|
|
|
|
def get_env_float_non_negative(name: str, default: Optional[float]) -> Optional[float]:
|
|
"""Get environment variable as a non-negative float.
|
|
|
|
Args:
|
|
name: The name of the environment variable.
|
|
default: Default value to use if the environment variable is not set.
|
|
|
|
Returns:
|
|
The environment variable value as a non-negative float.
|
|
|
|
Raises:
|
|
ValueError: If the value cannot be converted to a float or is negative.
|
|
"""
|
|
return _get_env_value(name, default, float, lambda x: x >= 0, "non negative")
|
|
|
|
|
|
def get_env_str(name: str, default: Optional[str]) -> Optional[str]:
|
|
"""Get environment variable as a string.
|
|
|
|
Args:
|
|
name: The name of the environment variable.
|
|
default: Default value to use if the environment variable is not set.
|
|
|
|
Returns:
|
|
The environment variable value as a string.
|
|
Returns `None` if default is `None` and value not found.
|
|
"""
|
|
return _get_env_value(name, default, str)
|
|
|
|
|
|
def get_env_bool(name: str, default: str) -> bool:
|
|
"""Get environment variable as a boolean.
|
|
|
|
Environment variable values of "1" are interpreted as True, all others as False.
|
|
|
|
Args:
|
|
name: The name of the environment variable.
|
|
default: Default value to use if the environment variable is not set.
|
|
Expects "0" or "1".
|
|
|
|
Returns:
|
|
True if the environment variable value is "1", False otherwise.
|
|
"""
|
|
env_value_str = _get_env_value(name, default, str)
|
|
return env_value_str == "1"
|
|
|
|
|
|
# Environment variables that are fully deprecated and will be ignored.
|
|
_fully_deprecated_env_vars = {
|
|
"RAY_SERVE_HTTP_KEEP_ALIVE_TIMEOUT_S": "http_options.keep_alive_timeout_s",
|
|
"RAY_SERVE_ROUTER_RETRY_INITIAL_BACKOFF_S": "request_router_config.initial_backoff_s",
|
|
"RAY_SERVE_ROUTER_RETRY_BACKOFF_MULTIPLIER": "request_router_config.backoff_multiplier",
|
|
"RAY_SERVE_ROUTER_RETRY_MAX_BACKOFF_S": "request_router_config.max_backoff_s",
|
|
}
|
|
|
|
|
|
def _deprecation_warning(name: str) -> None:
|
|
"""Log replacement warning for wrong or legacy environment variables.
|
|
|
|
TODO: remove this function for the '3.0.0' release.
|
|
|
|
Args:
|
|
name: Environment variable name.
|
|
"""
|
|
|
|
def get_new_name(name: str) -> str:
|
|
if name == "RAY_SERVE_HANDLE_METRIC_PUSH_INTERVAL_S":
|
|
return "RAY_SERVE_HANDLE_AUTOSCALING_METRIC_PUSH_INTERVAL_S"
|
|
elif name == "SERVE_REQUEST_PROCESSING_TIMEOUT_S":
|
|
return "RAY_SERVE_REQUEST_PROCESSING_TIMEOUT_S"
|
|
else:
|
|
return f"{required_prefix}{name}"
|
|
|
|
change_version = "3.0.0"
|
|
required_prefix = "RAY_SERVE_"
|
|
|
|
if (
|
|
name in _wrong_names_white_list
|
|
or name == "RAY_SERVE_HANDLE_METRIC_PUSH_INTERVAL_S"
|
|
):
|
|
new_name = get_new_name(name)
|
|
warnings.warn(
|
|
f"Starting from version `{change_version}` environment variable "
|
|
f"`{name}` will be deprecated. Please use `{new_name}` instead.",
|
|
FutureWarning,
|
|
stacklevel=4,
|
|
)
|
|
|
|
|
|
def warn_if_deprecated_env_var_set(name: str) -> None:
|
|
"""Warn if a fully deprecated environment variable is set.
|
|
|
|
Args:
|
|
name: Environment variable name.
|
|
"""
|
|
if name in _fully_deprecated_env_vars and os.environ.get(name):
|
|
config_option = _fully_deprecated_env_vars[name]
|
|
warnings.warn(
|
|
f"`{name}` environment variable will be deprecated in the future. "
|
|
f"Use `{config_option}` in the Serve config instead.",
|
|
DeprecationWarning,
|
|
stacklevel=2,
|
|
)
|