diff --git a/backend/api_v2/api_deployment_views.py b/backend/api_v2/api_deployment_views.py index e13b211b4e..852c8de203 100644 --- a/backend/api_v2/api_deployment_views.py +++ b/backend/api_v2/api_deployment_views.py @@ -11,8 +11,8 @@ from rest_framework.request import Request from rest_framework.response import Response from rest_framework.serializers import Serializer -from utils.enums import CeleryTaskState from workflow_manager.workflow_v2.dto import ExecutionResponse +from workflow_manager.workflow_v2.enums import ExecutionStatus from api_v2.api_deployment_dto_registry import ApiDeploymentDTORegistry from api_v2.constants import ApiExecution @@ -92,6 +92,23 @@ def get( api_name: str, deployment_execution_dto: DeploymentExecutionDTO, ) -> Response: + """Get workflow execution status and results. + + Returns appropriate HTTP status codes based on execution state: + - 200 OK: COMPLETED, EXECUTING, PENDING (valid states) + - 406 Not Acceptable: Result already acknowledged + - 422 Unprocessable Entity: ERROR, STOPPED (failure states) + + Args: + request: HTTP request object + org_name: Organization name + api_name: API deployment name + deployment_execution_dto: Validated deployment context + + Returns: + Response with execution status and results + """ + # Validate query parameters serializer = ExecutionQuerySerializer(data=request.query_params) serializer.is_valid(raise_exception=True) @@ -99,21 +116,36 @@ def get( include_metadata = serializer.validated_data.get(ApiExecution.INCLUDE_METADATA) include_metrics = serializer.validated_data.get(ApiExecution.INCLUDE_METRICS) - # Fetch execution status + # Fetch current execution status response: ExecutionResponse = DeploymentHelper.get_execution_status(execution_id) - # Determine response status - response_status = status.HTTP_422_UNPROCESSABLE_ENTITY - if response.execution_status == CeleryTaskState.COMPLETED.value: - response_status = status.HTTP_200_OK - if not settings.ENABLE_HIGHLIGHT_API_DEPLOYMENT: - response.remove_result_metadata_keys(["highlight_data"]) - if not include_metadata: - response.remove_result_metadata_keys() - if not include_metrics: - response.remove_result_metrics() + + # Check if result was already acknowledged (one-time access) if response.result_acknowledged: - response_status = status.HTTP_406_NOT_ACCEPTABLE - response.result = "Result already acknowledged" + return Response( + data={ + "status": response.execution_status, + "message": "Result already acknowledged", + }, + status=status.HTTP_406_NOT_ACCEPTABLE, + ) + + # Determine HTTP status code based on execution state + if response.execution_status == ExecutionStatus.COMPLETED: + # Successful completion - prepare result data + response_status = status.HTTP_200_OK + self._filter_response_data(response, include_metadata, include_metrics) + + elif response.execution_status in ( + ExecutionStatus.EXECUTING, + ExecutionStatus.PENDING, + ): + # Valid in-progress states - return 200 OK (not 422 as before) + response_status = status.HTTP_200_OK + + else: + # Error states (STOPPED, ERROR, etc.) - indicate processing failure + response_status = status.HTTP_422_UNPROCESSABLE_ENTITY + return Response( data={ "status": response.execution_status, @@ -122,6 +154,28 @@ def get( status=response_status, ) + def _filter_response_data( + self, response: ExecutionResponse, include_metadata: bool, include_metrics: bool + ) -> None: + """Filter response data based on client preferences and settings. + + Args: + response: Execution response to filter + include_metadata: Whether to include metadata in response + include_metrics: Whether to include metrics in response + """ + # Remove highlight data if not enabled globally + if not settings.ENABLE_HIGHLIGHT_API_DEPLOYMENT: + response.remove_result_metadata_keys(["highlight_data"]) + + # Remove metadata if not requested by client + if not include_metadata: + response.remove_result_metadata_keys() + + # Remove metrics if not requested by client + if not include_metrics: + response.remove_result_metrics() + class APIDeploymentViewSet(viewsets.ModelViewSet): permission_classes = [IsOwner]