Files
flyer-crawler.projectium.com/docs/adr/0051-asynchronous-context-propagation.md
Torben Sorensen 11aeac5edd
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 1m10s
whoa - so much - new features (UPC,etc) - Sentry for app logging! so much more !
2026-01-11 19:07:02 -08:00

1.7 KiB

ADR-051: Asynchronous Context Propagation

Date: 2026-01-11

Status: Accepted (Implemented)

Context

Debugging asynchronous workflows is difficult because the request_id generated at the API layer is lost when a task is handed off to a background queue (BullMQ). Logs from the worker appear disconnected from the user action that triggered them.

Decision

We will implement a context propagation pattern for all background jobs:

  1. Job Data Payload: All job data interfaces MUST include a meta object containing requestId, userId, and origin.
  2. Worker Logger Initialization: All BullMQ workers MUST initialize a child logger immediately upon processing a job, using the metadata passed in the payload.
  3. Correlation: The worker's logger must use the same request_id as the initiating API request.

Implementation

// 1. Enqueueing (API Layer)
await queue.add('process-flyer', {
  ...data,
  meta: {
    requestId: req.log.bindings().request_id, // Propagate ID
    userId: req.user.id,
  },
});

// 2. Processing (Worker Layer)
const worker = new Worker('queue', async (job) => {
  const { requestId, userId } = job.data.meta || {};

  // Create context-aware logger for this specific job execution
  const jobLogger = logger.child({
    request_id: requestId || uuidv4(), // Use propagated ID or generate new
    user_id: userId,
    job_id: job.id,
    service: 'worker',
  });

  try {
    await processJob(job.data, jobLogger); // Pass logger down
  } catch (err) {
    jobLogger.error({ err }, 'Job failed');
    throw err;
  }
});

Consequences

Positive: Complete traceability from API request -> Queue -> Worker execution. Drastically reduces time to find "what happened" to a specific user request.