diff --git a/src/aare/common/exception_handler.py b/src/aare/common/exception_handler.py index dc764783..72e4bce3 100644 --- a/src/aare/common/exception_handler.py +++ b/src/aare/common/exception_handler.py @@ -17,6 +17,26 @@ class TransformationInvalidException(Exception): return self.message +class StateTransitionFailed(Exception): + def __init__(self, message: str = "Beamline state transition failed"): + super().__init__(message) + self.message = message + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class MaintenanceStateException(Exception): + def __init__(self, message: str = "Beamline is in Maintenance state"): + super().__init__(message) + self.message = message + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + class DataCollectionException(Exception): def __init__(self, message: str = "Data collection failed"): super().__init__(message) @@ -409,4 +429,33 @@ class MagnetPositionSensorErorr(Exception): ) def __str__(self) -> str: - return self.message \ No newline at end of file + return self.message + +class BECCommunicationError(Exception): + def __init__( + self, + message: str = "BEC communication error", + *, + exception: Exception | None = None, + operation: str | None = None, + endpoint: str | None = None, + base_url: str | None = None, + ): + self.message = message + self.operation = operation + self.exception = exception + self.endpoint = endpoint + self.base_url = base_url + logger.error( + message, + extra={ + "device": "bec", + "operation": operation, + "endpoint": endpoint, + "base_url": base_url, + "exception": exception, + }, + ) + + def __str__(self) -> str: + return self.message diff --git a/src/aare/daq/server_exception_handler.py b/src/aare/daq/server_exception_handler.py index 3728eb4a..35853320 100644 --- a/src/aare/daq/server_exception_handler.py +++ b/src/aare/daq/server_exception_handler.py @@ -13,12 +13,15 @@ from aare.common.exception_handler import ( CriticalTellException, LoopCenteringFailed, TransformationInvalidException, + StateTransitionFailed, + MaintenanceStateException, BeamlineBusyException, AuthenticationException, SampleException, UserRightsException, SmargonCommunicationError, TellCommunicationError, + BECCommunicationError, JFJochCommunicationError, AerotechCommunicationError, DataCollectionException, @@ -237,6 +240,22 @@ def register_exception_handlers(app) -> None: ), ) + @app.exception_handler(BECCommunicationError) + async def bec_comm_handler(request: Request, exc: BECCommunicationError) -> JSONResponse: + return JSONResponse( + status_code=api_status.HTTP_503_SERVICE_UNAVAILABLE, + content=_error_payload( + code="BEC_UNAVAILABLE", + message=str(exc) or "BEC is unavailable", + extra={ + "operation": getattr(exc, "operation", None), + "endpoint": getattr(exc, "endpoint", None), + "base_url": getattr(exc, "base_url", None), + }, + ), + ) + + @app.exception_handler(JFJochCommunicationError) async def jfjoch_comm_handler(request: Request, exc: JFJochCommunicationError) -> JSONResponse: return JSONResponse(