Skip to content

Commit f78f80b

Browse files
cgillumCopilot
andcommitted
Create per-operation Server spans for entity batches
Each entity operation in a batch may come from a different orchestration with its own trace context. Create individual Server spans per operation instead of a single span for the whole batch, so each operation's span is correctly parented under its corresponding Client span. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 764c94a commit f78f80b

1 file changed

Lines changed: 27 additions & 12 deletions

File tree

src/Worker/Grpc/GrpcDurableTaskWorker.Processor.cs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -900,17 +900,28 @@ async Task OnRunEntityBatchAsync(
900900
var coreEntityId = DTCore.Entities.EntityId.FromString(batchRequest.InstanceId!);
901901
EntityId entityId = new(coreEntityId.Name, coreEntityId.Key);
902902

903-
// Start a Server trace span for entity operation execution using the first operation's
904-
// trace context. In multi-operation batches, only the first operation's trace context is
905-
// used as the parent. This is acceptable because entity batches are typically single-operation,
906-
// and individual Client spans are emitted per-operation in the orchestrator replay path.
907-
OperationRequest? firstOp = batchRequest.Operations?.FirstOrDefault();
908-
using Activity? traceActivity = TraceHelper.StartTraceActivityForEntityOperation(
909-
entityId.Name,
910-
firstOp?.Operation,
911-
batchRequest.InstanceId!,
912-
firstOp?.TraceContext?.TraceParent,
913-
firstOp?.TraceContext?.TraceState);
903+
// Start a Server trace span for each entity operation in the batch.
904+
// Each operation may come from a different orchestration with its own trace context,
905+
// so we create individual spans to preserve correct parent-child relationships.
906+
List<Activity>? traceActivities = null;
907+
if (batchRequest.Operations is { Count: > 0 })
908+
{
909+
foreach (OperationRequest op in batchRequest.Operations)
910+
{
911+
Activity? activity = TraceHelper.StartTraceActivityForEntityOperation(
912+
entityId.Name,
913+
op.Operation,
914+
batchRequest.InstanceId!,
915+
op.TraceContext?.TraceParent,
916+
op.TraceContext?.TraceState);
917+
918+
if (activity != null)
919+
{
920+
traceActivities ??= [];
921+
traceActivities.Add(activity);
922+
}
923+
}
924+
}
914925

915926
TaskName name = new(entityId.Name);
916927

@@ -961,7 +972,11 @@ async Task OnRunEntityBatchAsync(
961972
FailureDetails = new FailureDetails(frameworkException),
962973
};
963974

964-
traceActivity?.SetStatus(ActivityStatusCode.Error, frameworkException.Message);
975+
traceActivities?.ForEach(a => a.SetStatus(ActivityStatusCode.Error, frameworkException.Message));
976+
}
977+
finally
978+
{
979+
traceActivities?.ForEach(a => a.Dispose());
965980
}
966981

967982
P.EntityBatchResult response = batchResult.ToEntityBatchResult(

0 commit comments

Comments
 (0)