Skip to main content
Sandboxed processors run job processing code in isolated child processes or worker threads, preventing CPU-intensive operations from blocking the worker’s bookkeeping tasks and causing stalled jobs.

Why Use Sandboxed Processors?

When processors perform CPU-intensive operations, they block Node.js’s event loop, preventing the worker from:
  • Renewing job locks
  • Checking for stalled jobs
  • Responding to shutdown signals
  • Fetching new jobs
This leads to jobs being marked as “stalled” and re-processed unnecessarily. Sandboxed processors solve this by:
  • Running processor code in a separate process/thread
  • Keeping the main worker’s event loop free for bookkeeping
  • Enabling true parallel processing on multi-core systems
  • Preventing one job from blocking others

Creating a Sandboxed Processor

Define your processor in a separate file:
Then reference this file when creating the worker:
The processor file must be a path to a compiled JavaScript file (.js, .cjs, .mjs). If you’re using TypeScript, compile it first or use a file extension like .ts that your runtime supports.

File Path Options

BullMQ accepts several file path formats:

Standard String Path

URL instances are recommended on Windows to avoid path-related issues.

Automatic Extension Resolution

BullMQ automatically tries these extensions if not specified:

Worker Threads vs Child Processes

BullMQ supports two sandboxing mechanisms:

Child Processes (Default)

Uses Node’s child_process.fork() to spawn separate processes:
Characteristics:
  • Isolation: Complete process isolation
  • Memory: Separate memory space per process
  • Overhead: Higher resource usage
  • Stability: Process crash doesn’t affect main worker

Worker Threads (v3.13.0+)

Uses Node’s worker_threads module:
Characteristics:
  • Performance: Lower overhead than child processes
  • Memory: Shared memory possible (with SharedArrayBuffer)
  • Startup: Faster thread creation
  • Resource usage: Less demanding than processes
Worker threads are lighter than child processes but still require duplicating the Node.js runtime. They’re not as lightweight as threads in other languages.

Sandboxed Job API

The SandboxedJob interface provides a subset of the full Job API:

Handling Cancellation in Sandboxed Processors

Sandboxed processors automatically support cancellation through the AbortSignal:
Cancel from the main worker:

TypeScript with Sandboxed Processors

For TypeScript projects, compile your processor files:
1

Write processor in TypeScript

2

Configure TypeScript compilation

3

Compile TypeScript

4

Reference compiled file in worker

See this blog post for a detailed tutorial.

Concurrency with Sandboxed Processors

Set concurrency to match your CPU cores:
For mixed workloads:

Error Handling

Errors in sandboxed processors are caught and mark the job as failed:
Listen for failures in the main worker:

Performance Considerations

Process/Thread Overhead

Each sandboxed job requires spawning or reusing a process/thread:

When NOT to Use Sandboxing

Sandboxing adds overhead. Don’t use it for:
  • I/O-bound operations: Database queries, HTTP requests, file I/O
  • Fast computations: Operations that complete in milliseconds
  • Low CPU usage: Tasks that don’t block the event loop

Monitoring Sandboxed Workers

Best Practices

1

Use sandboxing for CPU-intensive work only

Reserve sandboxing for computations, image processing, video encoding, etc.
2

Match concurrency to CPU cores

3

Prefer worker threads for most use cases

Worker threads have lower overhead than child processes.
4

Keep processor files self-contained

Minimize dependencies in processor files to reduce memory usage.
5

Handle errors gracefully

Catch and log errors in processors to aid debugging.
6

Monitor resource usage

Watch memory and CPU usage to tune concurrency.

Concurrency

Configure parallel processing

Stalled Jobs

Understand stalled job recovery

Cancelling Jobs

Cancel sandboxed jobs

Worker Options

Configure worker behavior

API Reference