-
Notifications
You must be signed in to change notification settings - Fork 196
fix(atenet): propagate trace context through router and namespace span/metric attrs #429
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -91,6 +91,11 @@ type ActorResumer struct { | |
| apiClient ateapipb.ControlClient | ||
| flight singleflight.Group | ||
|
|
||
| // tracer records the ResumeActor span. Defaults to the package-level | ||
| // router tracer; injectable for tests so they can assert span lineage | ||
| // without swapping the global TracerProvider. | ||
| tracer trace.Tracer | ||
|
|
||
| // parkEnabled makes transient worker-pool saturation (FailedPrecondition) | ||
| // retryable, so a request is parked and retried until budget rather than | ||
| // failing immediately. | ||
|
|
@@ -124,9 +129,19 @@ func withParking(cfg ParkedRequestConfig) resumerOption { | |
| } | ||
| } | ||
|
|
||
| // withTracer overrides the tracer used to record the ResumeActor span. Tests | ||
| // use this to capture spans with a local TracerProvider instead of swapping | ||
| // the process-global one. | ||
| func withTracer(tracer trace.Tracer) resumerOption { | ||
| return func(r *ActorResumer) { | ||
| r.tracer = tracer | ||
| } | ||
| } | ||
|
|
||
| func NewActorResumer(apiClient ateapipb.ControlClient, opts ...resumerOption) *ActorResumer { | ||
| r := &ActorResumer{ | ||
| apiClient: apiClient, | ||
| tracer: otel.Tracer(routerServiceName), | ||
| budget: failFastResumeBudget, | ||
| backoff: resumeBackoff(defaultParkedRequestRetryInterval, | ||
| defaultParkedRequestRetryFactor, defaultParkedRequestRetryJitter), | ||
|
|
@@ -161,7 +176,7 @@ func (r *ActorResumer) retryable(err error) bool { | |
| // requests within the process and, when parking is enabled, holds the request | ||
| // while retrying transient failures until the budget elapses. | ||
| func (r *ActorResumer) ResumeActor(ctx context.Context, actorRef resources.ActorRef) (*ateapipb.Actor, ResumeOutcome, error) { | ||
| ctx, span := otel.Tracer(routerServiceName).Start(ctx, "ResumeActor", | ||
| ctx, span := r.tracer.Start(ctx, "ResumeActor", | ||
| trace.WithAttributes(ateattr.ActorRefAttributes(actorRef)...)) | ||
| defer span.End() | ||
|
|
||
|
|
@@ -179,6 +194,11 @@ func (r *ActorResumer) ResumeActor(ctx context.Context, actorRef resources.Actor | |
| // one control-plane RPC per hot actor (see docs/request-parking.md). | ||
| bgCtx, bgCancel := context.WithTimeout(context.Background(), r.budget) | ||
| defer bgCancel() | ||
| // Propagate the caller's span context into the background context so the | ||
| // gRPC spans created by the flight are children of ResumeActor rather | ||
| // than starting a fresh root trace. Without this, singleflight's | ||
| // context.Background() detaches the trace chain at the resumer. | ||
| bgCtx = trace.ContextWithSpanContext(bgCtx, trace.SpanContextFromContext(ctx)) | ||
|
Contributor
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. This looks good, but can you please add test asserting the resume child span shares the parent traceid?
Author
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. Done! Added TestActorResumer_ResumeChildSharesParentTraceID - sets up a local TracerProvider + in-memory exporter, starts a parent span, calls ResumeActor, and asserts the ResumeActor span shares the parent''s trace ID and parent span ID. |
||
|
|
||
| backoff := r.backoff | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're not setting
AppendAction, so this defaults toAPPEND_IF_EXISTS_OR_ADD. The request already has a traceparent, so Envoy appends a second value and not replace it. The w3c propagator receives a multi value traceparent, which is invalid per spec, so the worker starts a fresh root span.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch! I''ve set AppendAction to OVERWRITE_IF_EXISTS_OR_ADD on all injected trace headers so Envoy replaces the existing traceparent instead of appending a second (invalid) value.