All Products
Search
Document Center

Application Real-Time Monitoring Service:Maintain trace continuity in Asynq versions earlier than v0.26.0

Last Updated:Mar 14, 2026

This topic describes how to maintain trace continuity in Asynq versions earlier than v0.26.0.

Solution

Asynq versions earlier than v0.26.0 do not include a carrier within the `Task` `struct` to propagate the `SpanContext`. To maintain trace continuity, you must manually pass the trace context within the payload.

// Task represents a unit of work to be performed.
type Task struct {
    // typename indicates the type of task to be performed.
    typename string

    // payload holds data needed to perform the task.
    payload []byte

    // opts holds options for the task.
    opts []Option

    // w is the ResultWriter for the task.
    w *ResultWriter
}

For example, if the data `struct` for the `Task` payload is as follows:

type WelcomeEmailPayload struct {
	UserID   int    `json:"user_id"`
	Email    string `json:"email"`
	Username string `json:"username"`
}

You can add a `field` to the `struct` to carry the context, as shown below:

type WelcomeEmailPayload struct {
	UserID   int    `json:"user_id"`
	Email    string `json:"email"`
	Username string `json:"username"`
    Header   map[string]string `json:"header"`
}

Before creating a `Task`, you can create a `span` and write the context to the payload:

var task asynq.Task
tracer := otel.GetTracerProvider().Tracer("")
opts := append([]tracex.SpanStartOption{}, tracex.WithSpanKind(tracex.SpanKindClient))
// This is a demo. Write the trace information of the created span to the body and send it to the server-side. Adjust the code as needed.
ctx, span := tracer.Start(context.Background(), "Push Task", opts...)
var headerMap propagation.MapCarrier
headerMap = make(map[string]string)
otel.GetTextMapPropagator().Inject(ctx, headerMap)
// Set the span context in the header.
for k, v := range headerMap {
  task.Header[k] = v
}
defer span.End()
//... push task to server

You can restore the context where the `Task` is retrieved:

var headerMap propagation.MapCarrier
headerMap = make(map[string]string)
ctxRequest := context.Background()
// Get task header.
var task asynq.Task
for k, v := range task.Header {
  headerMap[k] = v
}
xxCtx := otel.GetTextMapPropagator().Extract(ctxRequest, headerMap)
tracer := otel.GetTracerProvider().Tracer("")
opts := append([]trace.SpanStartOption{}, trace.WithSpanKind(trace.SpanKindServer))
_, span := tracer.Start(xxCtx, "Recv Task", opts...)
defer span
//... other

This manual method propagates the `span` context.

After compiling the application, enable the OpenTelemetry setting for the application's probe. Restart the application for the changes to take effect.