|
2 | 2 | # Licensed under the MIT License. |
3 | 3 |
|
4 | 4 | import asyncio |
| 5 | +import contextlib |
5 | 6 | import inspect |
6 | 7 | import logging |
7 | 8 | import os |
|
26 | 27 | TInput = TypeVar("TInput") |
27 | 28 | TOutput = TypeVar("TOutput") |
28 | 29 |
|
| 30 | +# If `opentelemetry-sdk` is available, enable the tracer |
| 31 | +try: |
| 32 | + from opentelemetry import trace |
| 33 | + from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator |
| 34 | + |
| 35 | + otel_propagator = TraceContextTextMapPropagator() |
| 36 | + otel_tracer = trace.get_tracer(__name__) |
| 37 | +except ImportError: |
| 38 | + otel_tracer = None |
| 39 | + |
| 40 | + |
29 | 41 |
|
30 | 42 | class VersionNotRegisteredException(Exception): |
31 | 43 | pass |
@@ -839,31 +851,46 @@ def _execute_activity( |
839 | 851 | completionToken, |
840 | 852 | ): |
841 | 853 | instance_id = req.orchestrationInstance.instanceId |
842 | | - try: |
843 | | - executor = _ActivityExecutor(self._registry, self._logger) |
844 | | - result = executor.execute(instance_id, req.name, req.taskId, req.input.value) |
845 | | - res = pb.ActivityResponse( |
846 | | - instanceId=instance_id, |
847 | | - taskId=req.taskId, |
848 | | - result=ph.get_string_value(result), |
849 | | - completionToken=completionToken, |
850 | | - ) |
851 | | - except Exception as ex: |
852 | | - res = pb.ActivityResponse( |
853 | | - instanceId=instance_id, |
854 | | - taskId=req.taskId, |
855 | | - failureDetails=ph.new_failure_details(ex), |
856 | | - completionToken=completionToken, |
857 | | - ) |
858 | 854 |
|
859 | | - try: |
860 | | - stub.CompleteActivityTask(res) |
861 | | - except grpc.RpcError as rpc_error: # type: ignore |
862 | | - self._handle_grpc_execution_error(rpc_error, "activity") |
863 | | - except Exception as ex: |
864 | | - self._logger.exception( |
865 | | - f"Failed to deliver activity response for '{req.name}#{req.taskId}' of orchestration ID '{instance_id}' to sidecar: {ex}" |
| 855 | + if otel_tracer is not None: |
| 856 | + span_context = otel_tracer.start_as_current_span( |
| 857 | + name=f'activity: {req.name}', |
| 858 | + context=otel_propagator.extract(carrier={"traceparent": req.parentTraceContext.traceParent}), |
| 859 | + attributes={ |
| 860 | + "durabletask.task.instance_id": instance_id, |
| 861 | + "durabletask.task.id": req.taskId, |
| 862 | + "durabletask.activity.name": req.name, |
| 863 | + } |
866 | 864 | ) |
| 865 | + else: |
| 866 | + span_context = contextlib.nullcontext() |
| 867 | + |
| 868 | + with span_context: |
| 869 | + try: |
| 870 | + executor = _ActivityExecutor(self._registry, self._logger) |
| 871 | + result = executor.execute(instance_id, req.name, req.taskId, req.input.value) |
| 872 | + res = pb.ActivityResponse( |
| 873 | + instanceId=instance_id, |
| 874 | + taskId=req.taskId, |
| 875 | + result=ph.get_string_value(result), |
| 876 | + completionToken=completionToken, |
| 877 | + ) |
| 878 | + except Exception as ex: |
| 879 | + res = pb.ActivityResponse( |
| 880 | + instanceId=instance_id, |
| 881 | + taskId=req.taskId, |
| 882 | + failureDetails=ph.new_failure_details(ex), |
| 883 | + completionToken=completionToken, |
| 884 | + ) |
| 885 | + |
| 886 | + try: |
| 887 | + stub.CompleteActivityTask(res) |
| 888 | + except grpc.RpcError as rpc_error: # type: ignore |
| 889 | + self._handle_grpc_execution_error(rpc_error, "activity") |
| 890 | + except Exception as ex: |
| 891 | + self._logger.exception( |
| 892 | + f"Failed to deliver activity response for '{req.name}#{req.taskId}' of orchestration ID '{instance_id}' to sidecar: {ex}" |
| 893 | + ) |
867 | 894 |
|
868 | 895 |
|
869 | 896 | class _RuntimeOrchestrationContext( |
|
0 commit comments