Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/nexusrpc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from . import handler
from ._common import (
HandlerError,
HandlerErrorRetryBehavior,
HandlerErrorType,
InputT,
Link,
Expand All @@ -43,7 +42,6 @@
"handler",
"HandlerError",
"HandlerErrorType",
"HandlerErrorRetryBehavior",
"InputT",
"LazyValue",
"Link",
Expand Down
44 changes: 14 additions & 30 deletions src/nexusrpc/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,42 +48,42 @@ def __init__(
message: str,
*,
type: HandlerErrorType,
retry_behavior: Optional[HandlerErrorRetryBehavior] = None,
retryable_override: Optional[bool] = None,
):
"""
Initialize a new HandlerError.

:param message: A descriptive message for the error. This will become the
`message` in the resulting Nexus Failure object.
:param message: A descriptive message for the error. This will become
the `message` in the resulting Nexus Failure object.

:param type: The :py:class:`HandlerErrorType` of the error.

:param retry_behavior: Optional retry behavior for the error.
:param retryable_override: Optionally set whether the error should be
retried. By default, the error type is used
to determine this.
"""
super().__init__(message)
self._type = type
self._retry_behavior = retry_behavior
self._retryable_override = retryable_override

@property
def retry_behavior(self) -> Optional[HandlerErrorRetryBehavior]:
def retryable_override(self) -> Optional[bool]:
"""
The retry behavior set for this error.
The optional retryability override set when this error was created.
"""
return self._retry_behavior
return self._retryable_override

@property
def retryable(self) -> bool:
"""
Whether this error should be retried.

If :py:attr:`retry_behavior` is None, then the default behavior for the error
type is used. See
If :py:attr:`retryable_override` is None, then the default behavior for the
error type is used. See
https://github.com/nexus-rpc/api/blob/main/SPEC.md#predefined-handler-errors
"""
if self.retry_behavior == HandlerErrorRetryBehavior.RETRYABLE:
return True
elif self.retry_behavior == HandlerErrorRetryBehavior.NON_RETRYABLE:
return False
if self._retryable_override is not None:
return self._retryable_override

non_retryable_types = {
HandlerErrorType.BAD_REQUEST,
Expand Down Expand Up @@ -116,22 +116,6 @@ def type(self) -> HandlerErrorType:
return self._type


class HandlerErrorRetryBehavior(Enum):
"""
Retry behavior for a handler error.
"""

RETRYABLE = "RETRYABLE"
"""
The error should be retried.
"""

NON_RETRYABLE = "NON_RETRYABLE"
"""
The error should not be retried.
"""


class HandlerErrorType(Enum):
"""Nexus handler error types.

Expand Down
41 changes: 41 additions & 0 deletions tests/test_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from nexusrpc._common import HandlerError, HandlerErrorType


def test_handler_error_retryable_type():
retryable_error_type = HandlerErrorType.RESOURCE_EXHAUSTED
assert HandlerError(
"test",
type=retryable_error_type,
retryable_override=True,
).retryable

assert not HandlerError(
"test",
type=retryable_error_type,
retryable_override=False,
).retryable

assert HandlerError(
"test",
type=retryable_error_type,
).retryable


def test_handler_error_non_retryable_type():
non_retryable_error_type = HandlerErrorType.BAD_REQUEST
assert HandlerError(
"test",
type=non_retryable_error_type,
retryable_override=True,
).retryable

assert not HandlerError(
"test",
type=non_retryable_error_type,
retryable_override=False,
).retryable

assert not HandlerError(
"test",
type=non_retryable_error_type,
).retryable