Queue-Metrics Integration
Queue-Metrics Integration
Queue Monitor is built on top of laravel-queue-metrics and subscribes to its event system to capture per-job resource data.
How Integration Works
The integration happens through event subscription:
laravel-queue-metrics fires JobMetricsCompleted / JobMetricsFailed
↓
QueueMetricsSubscriber listens
↓
JobMonitorRepository updates job record
↓
CPU, memory metrics stored
Metrics Captured
CPU Time
Source: ProcessMetrics tracking in queue-metrics
Field: cpu_time_ms (decimal)
Calculation: User + System CPU time in milliseconds
$job = QueueMonitor::getJob($uuid);
echo "CPU Time: {$job->cpu_time_ms}ms";
Memory Peak
Source: ProcessMetrics tracking in queue-metrics
Field: memory_peak_mb (decimal)
Includes: Parent + child process memory
echo "Peak Memory: {$job->memory_peak_mb}MB";
File Descriptors
Source: Custom metrics from queue-metrics (if available)
Field: file_descriptors (integer)
Note: May not be available on all systems
if ($job->file_descriptors !== null) {
echo "File Descriptors: {$job->file_descriptors}";
}
Event Flow
1. Job Processing
// Laravel Queue fires JobProcessing event
// queue-monitor records job start
// queue-metrics starts ProcessMetrics tracking
ProcessMetrics::start("job_{$jobId}");
2. Job Completion
// Job finishes executing
// queue-metrics fires a per-job metrics event
event(new JobMetricsCompleted($jobId, $cpuTimeMs, $memoryMb, $workerMemoryLimitMb));
// queue-monitor's subscriber handles it
QueueMetricsSubscriber::handleJobMetricsCompleted($event);
3. Data Storage
QueueMetricsSubscriber subscribes to JobMetricsCompleted and
JobMetricsFailed (from cboxdk/laravel-queue-metrics) and updates the job
record with the metrics carried on the event:
$this->repository->update($jobMonitor->uuid, [
'cpu_time_ms' => $cpuTimeMs,
'memory_peak_mb' => $memoryMb,
'worker_memory_limit_mb' => $workerMemoryLimitMb,
]);
Matching Metrics to an Attempt
A retried or redelivered job has one row per attempt, all sharing one job_id.
JobMetricsCompleted and JobMetricsFailed carry that job_id but not the attempt
number, so the subscriber picks the row in this order:
- The attempt this worker started. When a job starts,
JobProcessingListenerremembers in the worker process which attempt it began. The metrics event is raised synchronously in the same worker when the job ends, so that attempt is the one that was measured. - The attempt still
processing. This is used when the worker did not see the start. - The latest attempt with no metrics yet. This is used when the row has already
moved to
completedorfailed.
The first rule matters when the broker redelivers a slow job to a second worker while
the first is still running it. The newer attempt is then the latest row, and the one
still processing, but its figures belong to the second worker. See
Job Lifecycle and Attempts.
Accessing Metrics
Via Model
use Cbox\LaravelQueueMonitor\Models\JobMonitor;
$job = JobMonitor::find($id);
echo "CPU: {$job->cpu_time_ms}ms\n";
echo "Memory: {$job->memory_peak_mb}MB\n";
echo "Duration: {$job->duration_ms}ms\n";
Via Facade
use Cbox\LaravelQueueMonitor\Facades\LaravelQueueMonitor as QueueMonitor;
$job = QueueMonitor::getJob($uuid);
if ($job->cpu_time_ms !== null) {
$cpuEfficiency = ($job->cpu_time_ms / $job->duration_ms) * 100;
echo "CPU Efficiency: {$cpuEfficiency}%\n";
}
Via API
curl /api/queue-monitor/jobs/{uuid}
Response includes metrics:
{
"data": {
"uuid": "...",
"metrics": {
"cpu_time_ms": 245.50,
"memory_peak_mb": 48.25,
"file_descriptors": 15,
"duration_ms": 1250,
"duration_seconds": 1.25
}
}
}
Analytics with Metrics
Statistics endpoints automatically include metric aggregations:
$stats = QueueMonitor::statistics();
echo "Avg CPU Time: {$stats['avg_cpu_time_ms']}ms\n";
echo "Max Memory: {$stats['max_memory_mb']}MB\n";
echo "Avg Duration: {$stats['avg_duration_ms']}ms\n";
Performance Analysis
Slow Jobs
Find jobs with high resource usage:
use Cbox\LaravelQueueMonitor\Models\JobMonitor;
// High CPU jobs
$cpuIntensive = JobMonitor::where('cpu_time_ms', '>', 1000)
->orderByDesc('cpu_time_ms')
->get();
// High memory jobs
$memoryIntensive = JobMonitor::where('memory_peak_mb', '>', 100)
->orderByDesc('memory_peak_mb')
->get();
// Slow jobs
$slowJobs = JobMonitor::slowJobs(5000) // > 5 seconds
->get();
Per-Queue Resource Usage
$queueStats = QueueMonitor::serverStatistics();
foreach ($queueStats as $stat) {
echo "Queue: {$stat['queue']}\n";
echo "Avg Duration: {$stat['avg_duration_ms']}ms\n";
echo "Total Jobs: {$stat['total']}\n";
}
Configuration
Persistence
Queue-metrics has two layers: instrumentation (per-job CPU/memory events) and persistence (aggregate storage of workers, throughput, baselines).
Queue Monitor only needs the instrumentation layer. If you don't use queue-autoscale or Prometheus export, you can disable persistence:
// config/queue-metrics.php
'persistence' => [
'enabled' => env('QUEUE_METRICS_PERSISTENCE', true),
],
With persistence off, per-job CPU/memory events still fire and Queue Monitor captures them. No storage backend required.
Note: cboxdk/laravel-queue-autoscale requires persistence enabled. It reads worker heartbeats, throughput, and baselines to make scaling decisions.
Storage Backend (when persistence is enabled)
'storage' => [
// 'redis' (default, recommended) or 'database'
'driver' => env('QUEUE_METRICS_STORAGE', 'redis'),
'connection' => env('QUEUE_METRICS_CONNECTION', 'default'),
'prefix' => 'queue_metrics',
// Recommended: 1000 for Redis, 500 for database
'max_samples_per_key' => env('QUEUE_METRICS_MAX_SAMPLES', 1000),
],
Redis is the recommended driver. Database is available for low-scale workloads (< 10 workers). See the installation guide for setup.
Metrics Collection
Queue-metrics instruments jobs automatically. No configuration needed beyond persistence and storage settings.
Integration Settings
Queue-monitor automatically subscribes to metrics events:
// No configuration needed - automatic integration
Troubleshooting
Metrics Not Appearing
-
Verify queue-metrics is installed:
composer show cboxdk/laravel-queue-metrics -
Check metrics collection is enabled:
config('queue-metrics.enabled'); // Should be true -
Verify events are firing:
Event::listen(JobMetricsCompleted::class, function ($event) { Log::info('Metrics recorded', ['job' => $event->jobId, 'cpu_ms' => $event->cpuTimeMs]); });
Partial Metrics
Some metrics may be unavailable on certain systems:
- File descriptors: Requires system support
- CPU time: Available on most *nix systems
- Memory: Always available via PHP
Performance Impact
Metrics collection has minimal overhead:
- CPU tracking: <1% overhead
- Memory tracking: <0.1% overhead
- Sample rate can be adjusted to reduce load
Best Practices
- Enable in all environments - Metrics are valuable in dev, staging, and production
- Use sample rates in high-traffic - Reduce overhead with sampling
- Monitor the monitors - Track queue-monitor's own performance
- Correlate with application metrics - Combine with APM tools
- Set up alerts - React to resource anomalies automatically