Skip to main content
A stalled job is a job that was being processed by a worker but didn’t complete within the expected time frame. BullMQ automatically detects and recovers stalled jobs, moving them back to the waiting state for reprocessing.

What Causes Stalled Jobs?

Jobs become stalled when:
  1. CPU-intensive operations block the event loop: The worker can’t renew the job’s lock
  2. Worker crashes: The process terminates unexpectedly
  3. Network issues: Worker loses connection to Redis
  4. Long-running jobs: Processing exceeds the lockDuration
  5. High system load: Worker can’t respond in time

How Stalled Detection Works

BullMQ uses a lock-based mechanism:
1

Worker acquires lock

When a worker starts processing a job, it acquires a lock with a TTL (time-to-live).
2

Lock renewal

The worker automatically renews the lock periodically while processing.
3

Stalled detection

If the lock expires (not renewed in time), the job is marked as stalled.
4

Recovery

The stalled checker moves the job back to waiting for another worker to process.

Stalled Job Configuration

lockDuration

The maximum time a job can be locked before being considered stalled:
Set lockDuration longer than your longest expected job duration. If jobs regularly take 45 seconds, use at least 60 seconds.

stalledInterval

How often the worker checks for stalled jobs:
Lower stalledInterval means faster recovery but slightly higher Redis load.

maxStalledCount

Maximum times a job can be recovered from stalled state before moving to failed:
After exceeding maxStalledCount, the job moves to the failed state.

skipStalledCheck

Disable stalled checking for a specific worker:
Even if one worker skips stalled checks, other workers on the same queue can still detect and recover stalled jobs.

skipLockRenewal

Disable automatic lock renewal:
Only use skipLockRenewal if you have a custom lock management strategy. Without renewal, jobs will become stalled after lockDuration.

Preventing Stalled Jobs

1. Keep Processors Async

Avoid blocking the event loop:

2. Use Sandboxed Processors for CPU Work

Isolate CPU-intensive operations:
See Sandboxed Processors for details.

3. Set Appropriate Lock Duration

Match lockDuration to job processing time:

4. Monitor and Adjust Concurrency

High concurrency with CPU work causes stalls:

Monitoring Stalled Jobs

Listen for stalled events:

Stalled Job Recovery Process

When a job becomes stalled:
  1. Detection: Worker’s stalled checker identifies the expired lock
  2. Event emission: stalled event is emitted with the job ID
  3. Move to waiting: Job is moved back to the waiting state
  4. Increment counter: Job’s stalled count is incremented
  5. Re-processing: Another worker (or the same one) picks up the job
  6. Failure on limit: If maxStalledCount is exceeded, job moves to failed

Troubleshooting Stalled Jobs

Frequent Stalling

Symptoms: Jobs stall repeatedly. Causes & Solutions:
  1. CPU blocking:
  2. Lock duration too short:
  3. High concurrency:

Jobs Fail After Multiple Stalls

Cause: Exceeding maxStalledCount. Solution: Increase maxStalledCount or fix the root cause:

No Stalled Detection

Cause: All workers have skipStalledCheck: true. Solution: Ensure at least one worker performs stalled checks:

Best Practices

1

Set lockDuration appropriately

Make it 1.5-2x your longest expected job duration.
2

Use sandboxing for CPU work

Prevent event loop blocking with sandboxed processors.
3

Monitor stalled events

Alert on frequent stalls to identify problematic jobs:
4

Adjust maxStalledCount

Set based on acceptable retry attempts for your use case.
5

Keep workers healthy

Ensure workers have sufficient resources (CPU, memory, network).
6

Test under load

Simulate high load to identify stalling issues before production.

Sandboxed Processors

Prevent stalls with process isolation

Concurrency

Configure parallel processing

Graceful Shutdown

Minimize stalls during shutdown

Cancelling Jobs

Handle lock renewal failures

API Reference