ForcePilot/backend/package/yuxi/channel/extensions/tlon/errors.py

78 lines
2.0 KiB
Python
Raw Normal View History

from yuxi.channel.errors import ErrorSeverity
class UrbitError(Exception):
pass
class UrbitUrlError(UrbitError):
pass
class UrbitHttpError(UrbitError):
def __init__(self, status: int, body: str = ""):
self.status = status
self.body = body
super().__init__(f"HTTP {status}: {body}")
@property
def severity(self) -> ErrorSeverity:
if self.status == 429:
return ErrorSeverity.RATE_LIMITED
if self.status in (401, 403):
return ErrorSeverity.FORBIDDEN
if self.status >= 500:
return ErrorSeverity.RETRYABLE
if self.status >= 400:
return ErrorSeverity.FATAL
return ErrorSeverity.RETRYABLE
class UrbitAuthError(UrbitError):
pass
class UrbitSSEError(UrbitError):
pass
class UrbitPokeError(UrbitError):
pass
class UrbitScryError(UrbitError):
pass
_ERROR_SEVERITY_MAP = {
UrbitAuthError: ErrorSeverity.FATAL,
UrbitSSEError: ErrorSeverity.RETRYABLE,
UrbitPokeError: ErrorSeverity.RETRYABLE,
UrbitScryError: ErrorSeverity.RETRYABLE,
UrbitUrlError: ErrorSeverity.FATAL,
}
def classify_error(error: BaseException) -> object:
from yuxi.channel.protocols import ClassifiedError
if isinstance(error, UrbitHttpError):
return ClassifiedError(severity=error.severity, original_error=error, error_message=str(error))
severity = ErrorSeverity.RETRYABLE
for exc_type, sev in _ERROR_SEVERITY_MAP.items():
if isinstance(error, exc_type):
severity = sev
break
return ClassifiedError(severity=severity, original_error=error, error_message=str(error))
def is_retryable(error: BaseException) -> bool:
if isinstance(error, UrbitHttpError):
return error.severity in (ErrorSeverity.RETRYABLE, ErrorSeverity.RATE_LIMITED)
if isinstance(error, UrbitAuthError):
return False
if isinstance(error, UrbitUrlError):
return False
return isinstance(error, UrbitError)