Files
2026-07-13 13:22:34 +08:00

79 lines
2.9 KiB
Python

import contextlib
from contextvars import ContextVar
from dataclasses import dataclass
from typing import Any
# A thread local variable to store the context of the current prediction request.
# This is particularly used to associate logs/traces with a specific prediction request in the
# caller side. The context variable is intended to be set by the called before invoking the
# predict method, using the set_prediction_context context manager.
_PREDICTION_REQUEST_CTX = ContextVar("mlflow_prediction_request_context", default=None)
@dataclass
class Context:
# A unique identifier for the current prediction request.
request_id: str | None = None
# Whether the current prediction request is as a part of MLflow model evaluation.
is_evaluate: bool = False
# The schema of the dependencies to be added into the tag of trace info.
dependencies_schemas: dict[str, Any] | None = None
# The logged model ID associated with the current prediction request
model_id: str | None = None
# The model serving endpoint name where the prediction request is made
endpoint_name: str | None = None
def __init__(
self,
request_id: str | None = None,
is_evaluate: bool = False,
dependencies_schemas: dict[str, Any] | None = None,
model_id: str | None = None,
endpoint_name: str | None = None,
# Accept extra kwargs so we don't need to worry backward compatibility
# when adding new attributes to the Context class
**kwargs,
):
self.request_id = request_id
self.is_evaluate = is_evaluate
self.dependencies_schemas = dependencies_schemas
self.model_id = model_id
self.endpoint_name = endpoint_name
def update(self, **kwargs):
for key, value in kwargs.items():
if hasattr(self, key):
setattr(self, key, value)
else:
raise AttributeError(f"Context has no attribute named '{key}'")
@contextlib.contextmanager
def set_prediction_context(context: Context | None):
"""
Set the context for the current prediction request. The context will be set as a thread-local
variable and will be accessible globally within the same thread.
Args:
context: The context for the current prediction request.
"""
if context and not isinstance(context, Context):
raise TypeError(f"Expected context to be an instance of Context, but got: {context}")
token = _PREDICTION_REQUEST_CTX.set(context)
try:
yield
finally:
_PREDICTION_REQUEST_CTX.reset(token)
def get_prediction_context() -> Context | None:
"""
Get the context for the current prediction request. The context is thread-local and is set
using the set_prediction_context context manager.
Returns:
The context for the current prediction request, or None if no context is set.
"""
return _PREDICTION_REQUEST_CTX.get()