Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Serve] Expose ApplicationStatus class to API docs (#34966) #48220

Merged
merged 10 commits into from
Oct 24, 2024
Merged
1 change: 1 addition & 0 deletions doc/source/serve/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ Content-Type: application/json

schema.ServeInstanceDetails
schema.APIType
schema.ApplicationStatus
schema.ApplicationDetails
schema.DeploymentDetails
schema.ReplicaDetails
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@

from ray._private.test_utils import wait_for_condition
from ray.serve._private.common import (
ApplicationStatus,
DeploymentStatus,
DeploymentStatusTrigger,
ProxyStatus,
ReplicaState,
)
from ray.serve._private.constants import SERVE_NAMESPACE
from ray.serve.schema import ServeInstanceDetails
from ray.serve.schema import ApplicationStatus, ServeInstanceDetails
from ray.serve.tests.conftest import * # noqa: F401 F403
from ray.tests.conftest import * # noqa: F401 F403
from ray.util.state import list_actors
Expand Down
4 changes: 2 additions & 2 deletions python/ray/serve/_private/application_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
from ray._private.utils import import_attr
from ray.exceptions import RuntimeEnvSetupError
from ray.serve._private.common import (
ApplicationStatus,
ApplicationStatusInfo,
DeploymentID,
DeploymentStatus,
DeploymentStatusInfo,
Expand Down Expand Up @@ -44,6 +42,8 @@
from ray.serve.generated.serve_pb2 import DeploymentLanguage
from ray.serve.schema import (
APIType,
ApplicationStatus,
ApplicationStatusInfo,
DeploymentDetails,
LoggingConfig,
ServeApplicationSchema,
Expand Down
10 changes: 7 additions & 3 deletions python/ray/serve/_private/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@
import ray
from ray.actor import ActorHandle
from ray.serve._private.common import (
ApplicationStatus,
DeploymentHandleSource,
DeploymentID,
DeploymentStatus,
DeploymentStatusInfo,
MultiplexedReplicaInfo,
StatusOverview,
)
from ray.serve._private.constants import (
CLIENT_CHECK_CREATION_POLLING_INTERVAL_S,
Expand All @@ -33,7 +31,13 @@
)
from ray.serve.generated.serve_pb2 import StatusOverview as StatusOverviewProto
from ray.serve.handle import DeploymentHandle, _HandleOptions
from ray.serve.schema import LoggingConfig, ServeApplicationSchema, ServeDeploySchema
from ray.serve.schema import (
ApplicationStatus,
LoggingConfig,
ServeApplicationSchema,
ServeDeploySchema,
StatusOverview,
)

logger = logging.getLogger(SERVE_LOGGER_NAME)

Expand Down
108 changes: 0 additions & 108 deletions python/ray/serve/_private/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,13 @@

from ray.actor import ActorHandle
from ray.serve._private.constants import SERVE_DEFAULT_APP_NAME
from ray.serve.generated.serve_pb2 import ApplicationStatus as ApplicationStatusProto
from ray.serve.generated.serve_pb2 import (
ApplicationStatusInfo as ApplicationStatusInfoProto,
)
from ray.serve.generated.serve_pb2 import DeploymentStatus as DeploymentStatusProto
from ray.serve.generated.serve_pb2 import (
DeploymentStatusInfo as DeploymentStatusInfoProto,
)
from ray.serve.generated.serve_pb2 import (
DeploymentStatusInfoList as DeploymentStatusInfoListProto,
)
from ray.serve.generated.serve_pb2 import (
DeploymentStatusTrigger as DeploymentStatusTriggerProto,
)
from ray.serve.generated.serve_pb2 import StatusOverview as StatusOverviewProto
from ray.serve.grpc_util import RayServegRPCContext

REPLICA_ID_FULL_ID_STR_PREFIX = "SERVE_REPLICA::"
Expand Down Expand Up @@ -115,41 +107,6 @@ class ReplicaState(str, Enum):
PENDING_MIGRATION = "PENDING_MIGRATION"


class ApplicationStatus(str, Enum):
NOT_STARTED = "NOT_STARTED"
DEPLOYING = "DEPLOYING"
DEPLOY_FAILED = "DEPLOY_FAILED"
RUNNING = "RUNNING"
UNHEALTHY = "UNHEALTHY"
DELETING = "DELETING"


@dataclass(eq=True)
class ApplicationStatusInfo:
status: ApplicationStatus
message: str = ""
deployment_timestamp: float = 0

def debug_string(self):
return json.dumps(asdict(self), indent=4)

def to_proto(self):
return ApplicationStatusInfoProto(
status=f"APPLICATION_STATUS_{self.status.name}",
message=self.message,
deployment_timestamp=self.deployment_timestamp,
)

@classmethod
def from_proto(cls, proto: ApplicationStatusInfoProto):
status = ApplicationStatusProto.Name(proto.status)[len("APPLICATION_STATUS_") :]
return cls(
status=ApplicationStatus(status),
message=proto.message,
deployment_timestamp=proto.deployment_timestamp,
)


class DeploymentStatus(str, Enum):
UPDATING = "UPDATING"
HEALTHY = "HEALTHY"
Expand Down Expand Up @@ -508,71 +465,6 @@ def from_proto(cls, proto: DeploymentStatusInfoProto):
)


@dataclass(eq=True)
class StatusOverview:
app_status: ApplicationStatusInfo
name: str = ""
deployment_statuses: List[DeploymentStatusInfo] = field(default_factory=list)

def debug_string(self):
return json.dumps(asdict(self), indent=4)

def get_deployment_status(self, name: str) -> Optional[DeploymentStatusInfo]:
"""Get a deployment's status by name.

Args:
name: Deployment's name.

Return (Optional[DeploymentStatusInfo]): Status with a name matching
the argument, if one exists. Otherwise, returns None.
"""

for deployment_status in self.deployment_statuses:
if name == deployment_status.name:
return deployment_status

return None

def to_proto(self):
# Create a protobuf for the Serve Application info
app_status_proto = self.app_status.to_proto()

# Create protobufs for all individual deployment statuses
deployment_status_protos = map(
lambda status: status.to_proto(), self.deployment_statuses
)

# Create a protobuf list containing all the deployment status protobufs
deployment_status_proto_list = DeploymentStatusInfoListProto()
deployment_status_proto_list.deployment_status_infos.extend(
deployment_status_protos
)

# Return protobuf encapsulating application and deployment protos
return StatusOverviewProto(
name=self.name,
app_status=app_status_proto,
deployment_statuses=deployment_status_proto_list,
)

@classmethod
def from_proto(cls, proto: StatusOverviewProto) -> "StatusOverview":
# Recreate Serve Application info
app_status = ApplicationStatusInfo.from_proto(proto.app_status)

# Recreate deployment statuses
deployment_statuses = []
for info_proto in proto.deployment_statuses.deployment_status_infos:
deployment_statuses.append(DeploymentStatusInfo.from_proto(info_proto))

# Recreate StatusInfo
return cls(
app_status=app_status,
deployment_statuses=deployment_statuses,
name=proto.name,
)


@dataclass(frozen=True)
class RunningReplicaInfo:
replica_id: ReplicaID
Expand Down
2 changes: 1 addition & 1 deletion python/ray/serve/_private/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
MultiplexedReplicaInfo,
NodeId,
RunningReplicaInfo,
StatusOverview,
TargetCapacityDirection,
)
from ray.serve._private.constants import (
Expand Down Expand Up @@ -68,6 +67,7 @@
ServeApplicationSchema,
ServeDeploySchema,
ServeInstanceDetails,
StatusOverview,
gRPCOptionsSchema,
)
from ray.util import metrics
Expand Down
8 changes: 2 additions & 6 deletions python/ray/serve/_private/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,15 @@
from ray import serve
from ray.actor import ActorHandle
from ray.serve._private.client import ServeControllerClient
from ray.serve._private.common import (
ApplicationStatus,
DeploymentID,
DeploymentStatus,
RequestProtocol,
)
from ray.serve._private.common import DeploymentID, DeploymentStatus, RequestProtocol
from ray.serve._private.constants import SERVE_DEFAULT_APP_NAME, SERVE_NAMESPACE
from ray.serve._private.deployment_state import ALL_REPLICA_STATES, ReplicaState
from ray.serve._private.proxy import DRAINING_MESSAGE
from ray.serve._private.usage import ServeUsageTag
from ray.serve._private.utils import TimerBase
from ray.serve.context import _get_global_client
from ray.serve.generated import serve_pb2, serve_pb2_grpc
from ray.serve.schema import ApplicationStatus

TELEMETRY_ROUTE_PREFIX = "/telemetry"
STORAGE_ACTOR_NAME = "storage"
Expand Down
120 changes: 117 additions & 3 deletions python/ray/serve/schema.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import logging
from collections import Counter
from dataclasses import dataclass, field
from dataclasses import asdict, dataclass, field
from enum import Enum
from typing import Any, Dict, List, Optional, Set, Union
from zlib import crc32
Expand All @@ -17,8 +18,8 @@
)
from ray._private.runtime_env.packaging import parse_uri
from ray.serve._private.common import (
ApplicationStatus,
DeploymentStatus,
DeploymentStatusInfo,
DeploymentStatusTrigger,
ProxyStatus,
ReplicaState,
Expand All @@ -34,6 +35,14 @@
from ray.serve._private.deployment_info import DeploymentInfo
from ray.serve._private.utils import DEFAULT
from ray.serve.config import ProxyLocation
from ray.serve.generated.serve_pb2 import ApplicationStatus as ApplicationStatusProto
from ray.serve.generated.serve_pb2 import (
ApplicationStatusInfo as ApplicationStatusInfoProto,
)
from ray.serve.generated.serve_pb2 import (
DeploymentStatusInfoList as DeploymentStatusInfoListProto,
)
from ray.serve.generated.serve_pb2 import StatusOverview as StatusOverviewProto
from ray.util.annotations import PublicAPI

# Shared amongst multiple schemas.
Expand Down Expand Up @@ -824,10 +833,115 @@ class DeploymentStatusOverview:
message: str


@PublicAPI(stability="stable")
class ApplicationStatus(str, Enum):
"""The current status of the application."""

NOT_STARTED = "NOT_STARTED"
DEPLOYING = "DEPLOYING"
DEPLOY_FAILED = "DEPLOY_FAILED"
RUNNING = "RUNNING"
UNHEALTHY = "UNHEALTHY"
DELETING = "DELETING"


@PublicAPI(stability="stable")
@dataclass(eq=True)
class ApplicationStatusInfo:
status: ApplicationStatus
message: str = ""
deployment_timestamp: float = 0

def debug_string(self):
return json.dumps(asdict(self), indent=4)

def to_proto(self):
return ApplicationStatusInfoProto(
status=f"APPLICATION_STATUS_{self.status.name}",
message=self.message,
deployment_timestamp=self.deployment_timestamp,
)

@classmethod
def from_proto(cls, proto: ApplicationStatusInfoProto):
status = ApplicationStatusProto.Name(proto.status)[len("APPLICATION_STATUS_") :]
return cls(
status=ApplicationStatus(status),
message=proto.message,
deployment_timestamp=proto.deployment_timestamp,
)


@PublicAPI(stability="stable")
@dataclass(eq=True)
class StatusOverview:
app_status: ApplicationStatusInfo
name: str = ""
deployment_statuses: List[DeploymentStatusInfo] = field(default_factory=list)

def debug_string(self):
return json.dumps(asdict(self), indent=4)

def get_deployment_status(self, name: str) -> Optional[DeploymentStatusInfo]:
"""Get a deployment's status by name.

Args:
name: Deployment's name.

Return (Optional[DeploymentStatusInfo]): Status with a name matching
the argument, if one exists. Otherwise, returns None.
"""

for deployment_status in self.deployment_statuses:
if name == deployment_status.name:
return deployment_status

return None

def to_proto(self):
# Create a protobuf for the Serve Application info
app_status_proto = self.app_status.to_proto()

# Create protobufs for all individual deployment statuses
deployment_status_protos = map(
lambda status: status.to_proto(), self.deployment_statuses
)

# Create a protobuf list containing all the deployment status protobufs
deployment_status_proto_list = DeploymentStatusInfoListProto()
deployment_status_proto_list.deployment_status_infos.extend(
deployment_status_protos
)

# Return protobuf encapsulating application and deployment protos
return StatusOverviewProto(
name=self.name,
app_status=app_status_proto,
deployment_statuses=deployment_status_proto_list,
)

@classmethod
def from_proto(cls, proto: StatusOverviewProto) -> "StatusOverview":
# Recreate Serve Application info
app_status = ApplicationStatusInfo.from_proto(proto.app_status)

# Recreate deployment statuses
deployment_statuses = []
for info_proto in proto.deployment_statuses.deployment_status_infos:
deployment_statuses.append(DeploymentStatusInfo.from_proto(info_proto))

# Recreate StatusInfo
return cls(
app_status=app_status,
deployment_statuses=deployment_statuses,
name=proto.name,
)


@PublicAPI(stability="alpha")
@dataclass
class ApplicationStatusOverview:
"""Describes the status of an application and all its deployments.
"""Describes the satus of an application and all its deployments.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Describes the satus of an application and all its deployments.
"""Describes the status of an application and all its deployments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch


Attributes:
status: The current status of the application.
Expand Down
Loading