Jobs and queues
Flare can collect information about queued jobs in your application:
- The job name and class
- The dispatch span (when one side of your application puts a job onto a queue)
- The processing span (when a queue worker pulls a job off the queue and runs it)
- Whether the job succeeded or failed, and the exception if it failed
Two recorders work together. QueueRecorder records the dispatch on the side that puts the job on the queue, and JobRecorder records the execution on the worker side.
This functionality is enabled by default and can be disabled per recorder:
$config->ignoreQueues();
$config->ignoreJobs();
You can also configure the maximum number of items tracked when an error occurs:
$config->collectJobs(maxItemsWithErrors: 10);
$config->collectQueues(maxItemsWithErrors: 10);
Ignoring specific jobs
You can drop traces for individual jobs by passing class or name patterns to collectJobs():
$config->collectJobs(
ignoredClasses: [
App\Jobs\HeartbeatJob::class,
'App\\Jobs\\Internal\\*',
],
);
Patterns are literal strings with * as a wildcard (the same syntax used by sampling rules). The same patterns are checked against both the job's name and class. See Subtask mode and ignored jobs below for how this interacts with subtask mode.
Recording the dispatch
When your application dispatches a job, call $flare->queue() to record a dispatch span. The recorder accepts a job attribute provider; use the helper for the common case:
$flare->queue()->recordStartFromQueuedJob(
jobName: 'SendWelcomeEmail',
jobClass: SendWelcomeEmail::class,
);
// ... push the job onto the queue ...
$flare->queue()->recordEnd();
If you want to continue the trace on the worker side (distributed tracing), capture the current traceparent from the tracer at dispatch time and store it on the job payload. A traceparent is a short header value defined by the W3C Trace Context specification (e.g. 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01) that carries the trace ID, the parent span ID, and the sampling decision across service boundaries. By passing it along with the job, the worker can pick the trace back up where the dispatcher left off instead of starting a fresh, disconnected one. The worker passes it to recordStart() on the job recorder.
Recording the execution
On the worker side, call $flare->job() around the job's run method. The job recorder also accepts a JobAttributesProvider:
$flare->job()->recordStartFromJob(
jobName: 'SendWelcomeEmail',
jobClass: SendWelcomeEmail::class,
traceparent: $payload->traceparent ?? null,
);
try {
$job->handle();
$flare->job()->recordEnd();
} catch (\Throwable $exception) {
$flare->job()->recordFailed($exception);
throw $exception;
}
The job recorder sets the entry point for the trace to queue and fills in the handler attributes from the job class.
Subtask mode and ignored jobs
Long-running queue workers boot once and process many jobs. Each job should be its own trace, not a span inside a single ever-growing trace. The lifecycle handles this for you in subtask mode:
while ($payload = $queue->pop()) {
$flare->lifecycle->startSubtask(traceparent: $payload->traceparent ?? null);
$flare->job()->recordStartFromJob(
jobName: $payload->name,
jobClass: $payload->class,
);
try {
$payload->handle();
$flare->job()->recordEnd();
} catch (\Throwable $exception) {
$flare->job()->recordFailed($exception);
}
$flare->lifecycle->endSubtask();
}
See Application lifecycle for the full subtask flow.
When a job is configured as ignored (for example, via $config->collectJobs(...) patterns), the job recorder behaves differently depending on the mode:
- In subtask mode, the entire subtask is unsampled. The trace is dropped before any spans are produced.
- In non-subtask mode (the job runs inside an outer trace, e.g. a synchronous job dispatched during a web request), the recorder pauses sampling around the ignored job and resumes it afterwards. The outer trace still captures the rest of the request.