Skip to content

worker_threads resource limits option not working with cluster module #41066

Description

@rafixer

Version

v17.2.0

Platform

20.6.0 Darwin Kernel Version 20.6.0: Mon Aug 30 06:12:21 PDT 2021; root:xnu-7195.141.6~3/RELEASE_X86_64 x86_64

Subsystem

worker_threads

What steps will reproduce the bug?

index.mjs

import http from 'http';
import cluster from 'cluster';
import path from 'path';
import { Worker } from 'worker_threads';

import v8 from 'v8';

if (cluster.isPrimary) {
  const workersEnv = {
    NODE_OPTIONS: `--max-old-space-size=512`
  };

  cluster.fork(workersEnv);

  const worker = new Worker('./worker.mjs', {
    resourceLimits: {
      maxOldGenerationSizeMb: 200,
    }
  });

  worker.postMessage('main');
} else {
  const worker = new Worker('./worker.mjs', {
    resourceLimits: {
      maxOldGenerationSizeMb: 200,
    }
  });

  worker.postMessage('worker');
}

worker.mjs

import v8 from 'v8';
import { parentPort } from 'worker_threads';

parentPort.on('message', (type) => {
  const { heap_size_limit } = v8.getHeapStatistics();
  console.log(`[${type}] heap_size_limit: ${heap_size_limit}`);
});

output:

[main] heap_size_limit: 260046848
[worker] heap_size_limit: 587202560

How often does it reproduce? Is there a required condition?

Whenever I use worker_threads module with a cluster - worker resourceLimits option is ignored.

What is the expected behavior?

Expected output:

[main] heap_size_limit: 260046848
[worker] heap_size_limit: 260046848

What do you see instead?

Max old space heap size probably was inherited from parent process (cluster) and resource limits option was ignored.

Additional information

This behavior may cause the memory leak on the worker to be handled incorrectly. Worker process will be killed if old heap space reach cluster process limits, not options I've passed.

Activity

  1. added
    clusterIssues and PRs related to the cluster subsystem.
    workerIssues and PRs related to the worker_threads module and Worker API.
    on Dec 3, 2021
  2. daeyeon commented on Apr 20, 2022

    @daeyeon
    Member

    The primary process above runs with no NODE_OPTIONS, so that the resourceLimits.maxOldGenerationSizeMb seems to work.

    A similar case can be observed without cluster module if --max-old-space-size is given in NODE_OPTIONS.

    // test.js
    const { Worker, isMainThread } = require('worker_threads');
    const v8 = require('v8');
    
    if (isMainThread) {
      new Worker(__filename, {
        resourceLimits: { maxOldGenerationSizeMb: 200 }
      });
    }
    const type = isMainThread ? 'main' : 'work';
    console.log(`[${type}] limit: ${v8.getHeapStatistics().heap_size_limit}`);

    Output

    > node test-worker.js
    [main] limit: 4345298944
    [work] limit: 260046848
    
    > NODE_OPTIONS=--max-old-space-size=512 node test.js
    [main] limit: 587202560
    [work] limit: 587202560

    When max_old_space_size is concurrently given from both NODE_OPTIONS and the constructor option, the one from NODE_OPTIONS seems to have more priority.

    node/deps/v8/src/heap/heap.cc

    Lines 5201 to 5207 in e64613d

    if (constraints.max_old_generation_size_in_bytes() > 0) {
    max_old_generation_size = constraints.max_old_generation_size_in_bytes();
    }
    if (FLAG_max_old_space_size > 0) {
    max_old_generation_size =
    static_cast<size_t>(FLAG_max_old_space_size) * MB;
    } else if (FLAG_max_heap_size > 0) {

  3. github-actions commented on Jun 25, 2026

    @github-actions
    Contributor

    This issue has been marked as stale due to 210 days of inactivity.
    It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.

  4. added
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Jun 25, 2026
  5. github-actions commented on Jul 26, 2026

    @github-actions
    Contributor

    This issue has been automatically closed after 30 days of inactivity following its stale status (no activity for a total of 120 days).
    If this is still relevant, feel free to reopen it or leave a comment with additional details so we can continue the discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    clusterIssues and PRs related to the cluster subsystem.staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.workerIssues and PRs related to the worker_threads module and Worker API.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions