-
Notifications
You must be signed in to change notification settings - Fork 67
[Logging I/O] Post inference hooks as background tasks #422
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5b72955
4bd88d7
52835ea
8820da7
0d222f3
19bc87c
32d554c
89ca0f2
932bcc9
b1cc1b2
2540626
c47eab6
82adeb4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
from celery import Celery, Task, states | ||
from model_engine_server.common.constants import DEFAULT_CELERY_TASK_NAME, LIRA_CELERY_TASK_NAME | ||
from model_engine_server.common.dtos.model_endpoints import BrokerType | ||
from model_engine_server.common.dtos.tasks import EndpointPredictV1Request | ||
from model_engine_server.core.celery import TaskVisibility, celery_app | ||
from model_engine_server.core.config import infra_config | ||
from model_engine_server.core.loggers import logger_name, make_logger | ||
|
@@ -25,45 +26,6 @@ class ErrorResponse(TypedDict): | |
error_metadata: str | ||
|
||
|
||
class ErrorHandlingTask(Task): | ||
"""Sets a 'custom' field with error in the Task response for FAILURE. | ||
|
||
Used when services are ran via the Celery backend. | ||
""" | ||
|
||
def after_return( | ||
self, status: str, retval: Union[dict, Exception], task_id: str, args, kwargs, einfo | ||
) -> None: | ||
"""Handler that ensures custom error response information is available whenever a Task fails. | ||
|
||
Specifically, whenever the task's :param:`status` is `"FAILURE"` and the return value | ||
:param:`retval` is an `Exception`, this handler extracts information from the `Exception` | ||
and constructs a custom error response JSON value (see :func:`error_response` for details). | ||
|
||
This handler then re-propagates the Celery-required exception information (`"exc_type"` and | ||
`"exc_message"`) while adding this new error response information under the `"custom"` key. | ||
""" | ||
if status == states.FAILURE and isinstance(retval, Exception): | ||
logger.warning(f"Setting custom error response for failed task {task_id}") | ||
|
||
info: dict = raw_celery_response(self.backend, task_id) | ||
result: dict = info["result"] | ||
err: Exception = retval | ||
|
||
error_payload = error_response("Internal failure", err) | ||
|
||
# Inspired by pattern from: | ||
# https://www.distributedpython.com/2018/09/28/celery-task-states/ | ||
self.update_state( | ||
state=states.FAILURE, | ||
meta={ | ||
"exc_type": result["exc_type"], | ||
"exc_message": result["exc_message"], | ||
"custom": json.dumps(error_payload, indent=False), | ||
}, | ||
) | ||
|
||
|
||
def raw_celery_response(backend, task_id: str) -> Dict[str, Any]: | ||
key_info: str = backend.get_key_for_task(task_id) | ||
info_as_str: str = backend.get(key_info) | ||
|
@@ -103,6 +65,47 @@ def create_celery_service( | |
else None, | ||
) | ||
|
||
class ErrorHandlingTask(Task): | ||
"""Sets a 'custom' field with error in the Task response for FAILURE. | ||
|
||
Used when services are ran via the Celery backend. | ||
""" | ||
|
||
def after_return( | ||
self, status: str, retval: Union[dict, Exception], task_id: str, args, kwargs, einfo | ||
) -> None: | ||
"""Handler that ensures custom error response information is available whenever a Task fails. | ||
|
||
Specifically, whenever the task's :param:`status` is `"FAILURE"` and the return value | ||
:param:`retval` is an `Exception`, this handler extracts information from the `Exception` | ||
and constructs a custom error response JSON value (see :func:`error_response` for details). | ||
|
||
This handler then re-propagates the Celery-required exception information (`"exc_type"` and | ||
`"exc_message"`) while adding this new error response information under the `"custom"` key. | ||
""" | ||
if status == states.FAILURE and isinstance(retval, Exception): | ||
logger.warning(f"Setting custom error response for failed task {task_id}") | ||
|
||
info: dict = raw_celery_response(self.backend, task_id) | ||
result: dict = info["result"] | ||
err: Exception = retval | ||
|
||
error_payload = error_response("Internal failure", err) | ||
|
||
# Inspired by pattern from: | ||
# https://www.distributedpython.com/2018/09/28/celery-task-states/ | ||
self.update_state( | ||
state=states.FAILURE, | ||
meta={ | ||
"exc_type": result["exc_type"], | ||
"exc_message": result["exc_message"], | ||
"custom": json.dumps(error_payload, indent=False), | ||
}, | ||
) | ||
request_params = args[0] | ||
request_params_pydantic = EndpointPredictV1Request.parse_obj(request_params) | ||
forwarder.post_inference_hooks_handler.handle(request_params_pydantic, retval, task_id) # type: ignore | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any way to pass in forwarder to the class rather than using encapsulation? maybe the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah I originally tried that approach but sadly you can't pass in custom args into the |
||
|
||
# See documentation for options: | ||
# https://docs.celeryproject.org/en/stable/userguide/tasks.html#list-of-options | ||
@app.task(base=ErrorHandlingTask, name=LIRA_CELERY_TASK_NAME, track_started=True) | ||
|
Uh oh!
There was an error while loading. Please reload this page.