exceptions.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. from typing import Optional
  2. import grpc
  3. from ray.exceptions import TaskCancelledError
  4. from ray.serve._private.common import DeploymentID
  5. from ray.util.annotations import PublicAPI
  6. @PublicAPI(stability="stable")
  7. class RayServeException(Exception):
  8. pass
  9. @PublicAPI(stability="stable")
  10. class gRPCStatusError(RayServeException):
  11. """Internal exception that wraps an exception with user-set gRPC status code.
  12. This is used to preserve user-set gRPC status codes when exceptions are raised
  13. in deployments. When a user sets a status code on the gRPC context before raising
  14. an exception, this wrapper carries that status code through the error handling
  15. path so the proxy can return the user's intended status code instead of INTERNAL.
  16. """
  17. def __init__(
  18. self,
  19. original_exception: BaseException,
  20. code: Optional[grpc.StatusCode] = None,
  21. details: Optional[str] = None,
  22. ):
  23. # Store attributes with underscore prefix to avoid conflicts with
  24. # Ray's exception handling (Ray uses 'cause' internally).
  25. self._original_exception = original_exception
  26. self._grpc_code = code
  27. self._grpc_details = details
  28. super().__init__(str(original_exception))
  29. @property
  30. def original_exception(self) -> BaseException:
  31. """The original exception that was raised."""
  32. return self._original_exception
  33. @property
  34. def grpc_code(self) -> Optional[grpc.StatusCode]:
  35. """The user-set gRPC status code, if any."""
  36. return self._grpc_code
  37. @property
  38. def grpc_details(self) -> Optional[str]:
  39. """The user-set gRPC status details, if any."""
  40. return self._grpc_details
  41. def __str__(self) -> str:
  42. return str(self._original_exception)
  43. @PublicAPI(stability="alpha")
  44. class BackPressureError(RayServeException):
  45. """Raised when max_queued_requests is exceeded on a DeploymentHandle."""
  46. def __init__(self, num_queued_requests: int, max_queued_requests: int):
  47. super().__init__(num_queued_requests, max_queued_requests)
  48. self._message = (
  49. f"Request dropped due to backpressure "
  50. f"(num_queued_requests={num_queued_requests}, "
  51. f"max_queued_requests={max_queued_requests})."
  52. )
  53. def __str__(self) -> str:
  54. return self._message
  55. @property
  56. def message(self) -> str:
  57. return self._message
  58. @PublicAPI(stability="alpha")
  59. class RequestCancelledError(RayServeException, TaskCancelledError):
  60. """Raise when a Serve request is cancelled."""
  61. def __init__(self, request_id: Optional[str] = None):
  62. self._request_id: Optional[str] = request_id
  63. def __str__(self):
  64. if self._request_id:
  65. return f"Request {self._request_id} was cancelled."
  66. else:
  67. return "Request was cancelled."
  68. @PublicAPI(stability="alpha")
  69. class DeploymentUnavailableError(RayServeException):
  70. """Raised when a Serve deployment is unavailable to receive requests.
  71. Currently this happens because the deployment failed to deploy.
  72. """
  73. def __init__(self, deployment_id: DeploymentID):
  74. self._deployment_id = deployment_id
  75. @property
  76. def message(self) -> str:
  77. return f"{self._deployment_id} is unavailable because it failed to deploy."