23 June, 20252 minute read

Integrate OpenTelemetry tracing with Google Cloud Tasks

Cloud Tasks is a basic queuing system available in GCP. Tasks inside a queue are dispatched to an HTTP endpoint for processing, and the details of where the task gets sent to is configured on the task itself. Like so:

Click to copy
import { CloudTasksClient } from '@google-cloud/tasks'; const tasks = new CloudTasksClient(); client.createTask({  // Queue ID  parent: client.queuePath('gcp-project-id', 'australia-southeast1', 'my-queue'),  // HTTP request details  httpRequest: {    headers: {      // ...    },    httpMethod: 'POST',    body: Buffer.from(JSON.stringify({      some: 'payload',    })).toString('base64'),  },});
You can specify any valid HTTP method and it will work just fine, but most people are using Cloud Tasks to POST a payload to an HTTP endpoint.

When you make an HTTP request normally, OpenTelemetry will propagate context across that HTTP request so that the trace for the callee's execution ends up linked to the caller's trace. This is unfortunately not the case for Cloud Tasks; you'll see a span for the network request to Google's servers for the createTask call and nothing further. Unlike the Pub/Sub client library, there is no enableOpenTelemetryTracing option you can set to opt-in to trace context propagation.

Fortunately it is pretty easy to fix this by using the propagation API from OpenTelemetry:

Click to copy
import { CloudTasksClient } from '@google-cloud/tasks';import { context, propagation } from '@opentelemetry/api'; const client = new CloudTasksClient(); const headers: Record<string, string> = {};propagation.inject(context.active(), headers); client.createTask({  // parent  httpRequest: {    headers,    // ...  },});

The propagation.inject method will inject propagation information according to whatever propagator(s) you have configured. If you are using the B3 context propagator, for instance, then the headers object will end up containing a b3 header value. So long as the worker on the other end of the queue is also set up with OpenTelemetry using the same context propagator, then everything will magically work after you make this change.

You should think about the lifecycle of your task handler when you propagate context like this. Cloud Tasks will automatically retry failed work according to the retry policy defined on the queue, and it is a legitimate pattern to implement polling of an external resource by having a task handler intentionally fail to trigger retries over an extended period of time. If you have such a task handler, it is probably not a good idea to propagate context. Doing so will make your trace much larger than it would otherwise be.

Don't want to miss out on new posts?

Join 100+ fellow engineers who subscribe for software insights, technical deep-dives, and valuable advice.

Get in touch 👋

If you're working on an innovative web or AI software product, then I'd love to hear about it. If we both see value in working together, we can move forward. And if not—we both had a nice chat and have a new connection.
Send me an email at hello@sophiabits.com