Skip to main content
Understanding parallelism and concurrency is crucial for maximizing throughput and efficiently processing jobs in BullMQ. While these terms are often used interchangeably, they have distinct meanings that affect how you configure your workers.

Parallelism

Parallelism means that two or more tasks run simultaneously on different CPU cores or machines. True parallel execution happens when:
  • You have multiple CPU cores available
  • Multiple machines are processing jobs
  • Tasks are genuinely executing at the exact same time

When Parallelism Helps

Parallelism provides maximum performance when:
  • Jobs are CPU-intensive: Calculations, data processing, image manipulation
  • Little to no I/O waiting: Minimal network calls, database queries, or file operations
  • Multiple cores available: Each parallel task gets its own CPU core
However, most software is continually blocked by slow I/O operations like:
  • Reading from the network
  • Writing to disk
  • Sending data via peripherals
  • Database queries
  • API calls
This is where concurrency becomes more important.

Concurrency

Concurrency means multiple tasks make progress by sharing CPU time through rapid context switching. Tasks give the impression of running in parallel, but they’re actually taking turns.

Node.js Event Loop

Node.js excels at concurrency through its single-threaded event loop:
  1. A job makes an async I/O call (e.g., database query)
  2. Instead of blocking, Node.js moves to the next task
  3. When the I/O completes, Node.js returns to finish the original task
  4. This gives the effect of parallel execution without the overhead
Concurrency is efficient because Node.js uses CPU time to execute code instead of waiting idle for async calls to complete.

BullMQ Concurrency

BullMQ’s concurrency setting controls how many jobs a single worker processes concurrently:

I/O-Heavy Jobs

For jobs with lots of I/O operations (API calls, database queries), increase concurrency:
Recommended concurrency for I/O-heavy jobs: 100-300

CPU-Intensive Jobs

For CPU-intensive jobs without I/O, keep concurrency low:
High concurrency with CPU-intensive jobs adds overhead without benefit. Use Sandboxed Processors instead for true parallelism.
Recommended concurrency for CPU-intensive jobs: 1-2

Threading in Node.js

Node.js supports worker threads, but they’re heavy:
  • Each thread requires a complete V8 VM
  • Memory overhead of several dozen megabytes per thread
  • Similar memory consumption to separate OS processes
See Sandboxed Processors for using worker threads with BullMQ.

Best Practices

Strategy 1: Worker Concurrency

Increase the concurrency factor for I/O-heavy jobs:
When to use:
  • Jobs perform API calls
  • Jobs query databases
  • Jobs read/write files
  • Jobs have significant wait times
Typical range: 50-300

Strategy 2: Multiple Workers

Run multiple worker instances for parallel processing:
Deploy across:
  • Multiple processes on the same machine
  • Multiple machines for horizontal scaling
When to use:
  • CPU-intensive jobs
  • Need for high availability
  • Scaling beyond a single machine

Strategy 3: Combine Both

For optimal performance, combine strategies:

Decision Matrix

I/O-Bound Jobs

  • Concurrency: High (100-300)
  • Workers: 1-2 per machine
  • Example: API calls, database queries

CPU-Bound Jobs

  • Concurrency: Low (1-2)
  • Workers: Match CPU cores
  • Example: Image processing, calculations

Mixed Workload

  • Concurrency: Medium (10-20)
  • Workers: 2-4 per machine
  • Example: Data processing with API calls

High Availability

  • Concurrency: Based on job type
  • Workers: Multiple machines
  • Example: Production systems

Performance Tuning

Start Conservative

Begin with low values and increase based on monitoring:

Monitor Resource Usage

Watch for bottlenecks:

Adjust Lock Duration

Higher concurrency may need longer locks:

Common Pitfalls

High concurrency with CPU-bound jobs: This adds overhead without benefit and can cause stalled jobs. Use sandboxing instead.
Too many workers: More workers than CPU cores won’t help CPU-bound jobs and wastes memory.
Ignoring I/O opportunities: Jobs with I/O operations benefit from higher concurrency. Don’t default to concurrency: 1.

Real-World Examples

Example 1: Email Service (I/O-Bound)

Example 2: Image Processing (CPU-Bound)

Example 3: Mixed Workload

Concurrency

Configure worker concurrency settings

Sandboxed Processors

Isolate CPU-intensive work in separate processes

Stalled Jobs

Understand and prevent stalled jobs

Rate Limiting

Control job processing rate

API Reference