Bird
Raised Fist0
Node.jsframework~20 mins

Worker pool pattern in Node.js - Practice Problems & Coding Challenges

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Challenge - 5 Problems
🎖️
Worker Pool Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
component_behavior
intermediate
2:00remaining
What is the output of this worker pool code snippet?
Consider this Node.js worker pool code using the 'worker_threads' module. What will be logged to the console?
Node.js
import { Worker, isMainThread, parentPort } from 'worker_threads';

if (isMainThread) {
  const worker = new Worker(new URL(import.meta.url));
  worker.on('message', (msg) => console.log('Main thread received:', msg));
  worker.postMessage('start');
} else {
  parentPort.on('message', (msg) => {
    if (msg === 'start') {
      parentPort.postMessage('worker done');
    }
  });
}
AMain thread received: worker done
BMain thread received: start
CNo output, code hangs
DSyntaxError due to import.meta.url usage
Attempts:
2 left
💡 Hint
Focus on the message events between main thread and worker.
state_output
intermediate
2:00remaining
How many tasks are processed concurrently in this worker pool?
Given this simplified worker pool code, how many tasks run at the same time?
Node.js
import { Worker } from 'worker_threads';

class WorkerPool {
  constructor(size) {
    this.size = size;
    this.workers = [];
    this.queue = [];
    this.active = 0;
  }

  runTask(task) {
    if (this.active < this.size) {
      this.active++;
      const worker = new Worker(task);
      worker.on('exit', () => {
        this.active--;
        if (this.queue.length) this.runTask(this.queue.shift());
      });
      this.workers.push(worker);
    } else {
      this.queue.push(task);
    }
  }
}

const pool = new WorkerPool(3);
pool.runTask('task1.js');
pool.runTask('task2.js');
pool.runTask('task3.js');
pool.runTask('task4.js');
AOnly 1 task runs at a time
B4 tasks run concurrently
C3 tasks run concurrently, 1 waits in queue
DNo tasks run because workers array is empty
Attempts:
2 left
💡 Hint
Check the active count compared to pool size.
🔧 Debug
advanced
2:30remaining
Why does this worker pool code cause a memory leak?
Identify the cause of the memory leak in this worker pool snippet.
Node.js
import { Worker } from 'worker_threads';

class Pool {
  constructor(size) {
    this.size = size;
    this.workers = [];
  }

  run(task) {
    const worker = new Worker(task);
    this.workers.push(worker);
    worker.on('exit', () => {
      console.log('Worker exited');
    });
  }
}

const pool = new Pool(2);
pool.run('task1.js');
pool.run('task2.js');
pool.run('task3.js');
AWorkers are never removed from the workers array after exit, causing memory leak
BThe pool size is ignored, so too many workers spawn
CWorkers are not started with worker.run(), causing them to hang
DMissing error event handler causes unhandled exceptions
Attempts:
2 left
💡 Hint
Check how the workers array is managed after workers exit.
📝 Syntax
advanced
2:00remaining
Which option correctly creates a worker pool with 4 workers?
Select the code snippet that correctly initializes a worker pool with 4 workers using 'worker_threads'.
Aconst pool = Array(4).fill(new Worker('worker.js'));
Bconst pool = Array.from({ length: 4 }, () => new Worker('worker.js'));
Cconst pool = new Array(4).forEach(() => new Worker('worker.js'));
Dconst pool = [new Worker('worker.js')] * 4;
Attempts:
2 left
💡 Hint
Remember how Array.fill() and Array.map() behave differently.
🧠 Conceptual
expert
2:30remaining
What is the main advantage of using a worker pool in Node.js?
Choose the best explanation for why a worker pool is used in Node.js applications.
ATo share memory directly between workers without serialization overhead
BTo run all tasks sequentially on the main thread to avoid concurrency issues
CTo automatically restart workers on failure without manual intervention
DTo limit the number of concurrent threads and reuse them for multiple tasks, improving performance and resource use
Attempts:
2 left
💡 Hint
Think about resource management and task handling.

Practice

(1/5)
1. What is the main purpose of using the worker pool pattern in Node.js?
easy
A. To increase the memory usage by creating many workers
B. To avoid using any background threads or workers
C. To slow down the program by running tasks one after another
D. To run multiple tasks concurrently using a fixed number of workers

Solution

  1. Step 1: Understand the worker pool pattern concept

    The worker pool pattern uses a limited number of workers to handle many tasks efficiently without creating too many threads.
  2. Step 2: Identify the main goal in Node.js context

    It allows running tasks concurrently but limits the number of workers to keep resource use balanced and improve speed.
  3. Final Answer:

    To run multiple tasks concurrently using a fixed number of workers -> Option D
  4. Quick Check:

    Worker pool = fixed workers + concurrent tasks [OK]
Hint: Worker pool means fixed workers handle many tasks concurrently [OK]
Common Mistakes:
  • Thinking worker pool creates unlimited workers
  • Believing it slows down the program
  • Confusing it with single-threaded execution
2. Which of the following is the correct way to create a worker pool using Node.js worker_threads module?
easy
A. const { Worker } = require('worker_threads'); const pool = new WorkerPool(4);
B. const pool = new WorkerPool(4); const { Worker } = require('worker_threads');
C. const { Worker } = require('worker_threads'); const pool = WorkerPool(4);
D. const pool = new Worker('worker.js', 4);

Solution

  1. Step 1: Import Worker correctly from worker_threads

    The correct import is: const { Worker } = require('worker_threads');
  2. Step 2: Create a worker pool instance properly

    Assuming a WorkerPool class exists, it should be instantiated with new WorkerPool(4); to create 4 workers.
  3. Final Answer:

    const { Worker } = require('worker_threads'); const pool = new WorkerPool(4); -> Option A
  4. Quick Check:

    Correct import + new instance = const { Worker } = require('worker_threads'); const pool = new WorkerPool(4); [OK]
Hint: Import Worker first, then create pool with new keyword [OK]
Common Mistakes:
  • Calling WorkerPool without new keyword
  • Wrong order of import and instantiation
  • Using Worker constructor incorrectly
3. Given this simplified worker pool code snippet, what will be logged to the console?
const { Worker } = require('worker_threads');

class WorkerPool {
  constructor(size) {
    this.workers = Array(size).fill(null).map(() => new Worker('./worker.js'));
  }
  runTask(task) {
    return new Promise((resolve) => {
      const worker = this.workers.pop();
      worker.once('message', (result) => {
        this.workers.push(worker);
        resolve(result);
      });
      worker.postMessage(task);
    });
  }
}

const pool = new WorkerPool(2);
pool.runTask('task1').then(console.log);
pool.runTask('task2').then(console.log);
medium
A. Runs tasks sequentially, logs task1 then task2
B. Outputs results of task1 and task2 as they complete, order not guaranteed
C. Only task1 result is logged, task2 is ignored
D. Throws an error because workers array is empty after first pop

Solution

  1. Step 1: Understand worker allocation and reuse

    The pool starts with 2 workers. Each runTask pops a worker, uses it, then pushes it back after message received.
  2. Step 2: Analyze concurrency and output order

    Both tasks run concurrently on separate workers. Results log as tasks complete, order may vary.
  3. Final Answer:

    Outputs results of task1 and task2 as they complete, order not guaranteed -> Option B
  4. Quick Check:

    Workers reused, tasks run concurrently [OK]
Hint: Workers pop and push back, tasks run in parallel [OK]
Common Mistakes:
  • Assuming workers array empties causing error
  • Thinking tasks run one after another
  • Believing only first task logs
4. Identify the bug in this worker pool code snippet and choose the correct fix:
class WorkerPool {
  constructor(size) {
    this.workers = [];
    for (let i = 0; i < size; i++) {
      this.workers.push(new Worker('./worker.js'));
    }
  }

  runTask(task) {
    if (this.workers.length === 0) {
      throw new Error('No workers available');
    }
    const worker = this.workers.pop();
    worker.once('message', (result) => {
      resolve(result);
      this.workers.push(worker);
    });
    worker.postMessage(task);
  }
}
medium
A. Replace pop() with shift() to get workers in order
B. Remove the check for empty workers array
C. Add a Promise wrapper around runTask and return it
D. Call worker.terminate() after task completes

Solution

  1. Step 1: Check runTask return and resolve usage

    runTask uses resolve inside callback but does not return a Promise or define resolve, causing error.
  2. Step 2: Fix by wrapping runTask in a Promise and returning it

    Wrap the logic inside return new Promise((resolve) => { ... }) so resolve is defined and caller can await result.
  3. Final Answer:

    Add a Promise wrapper around runTask and return it -> Option C
  4. Quick Check:

    runTask must return Promise with resolve [OK]
Hint: runTask uses resolve but lacks Promise wrapper [OK]
Common Mistakes:
  • Ignoring missing Promise causes runtime error
  • Removing worker availability check breaks logic
  • Terminating worker too early stops reuse
5. You want to process 10 CPU-heavy tasks using a worker pool of size 3. Which approach best ensures all tasks run efficiently without overloading the system?
hard
A. Create 3 workers, queue tasks, assign next task when a worker finishes
B. Create 10 workers, one per task, and run all at once
C. Run all tasks in the main thread sequentially without workers
D. Create 3 workers but assign all tasks to the first worker only

Solution

  1. Step 1: Understand resource limits and worker pool size

    Creating too many workers (10) can overload CPU and memory. Using 3 workers limits resource use.
  2. Step 2: Use a task queue to assign tasks as workers become free

    Queue tasks and assign next task to a worker when it finishes ensures all tasks run efficiently without overload.
  3. Final Answer:

    Create 3 workers, queue tasks, assign next task when a worker finishes -> Option A
  4. Quick Check:

    Fixed workers + queued tasks = efficient processing [OK]
Hint: Use fixed workers and queue tasks for efficiency [OK]
Common Mistakes:
  • Creating too many workers causing overload
  • Running tasks sequentially wasting concurrency
  • Assigning all tasks to one worker blocking others