| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent fcc4bf9 commit 886ef09
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1990,6 +1990,11 @@ meaning of the error depends on the specific function. | |||
| 1990 | 1990 | The `execArgv` option passed to the `Worker` constructor contains | |
| 1991 | 1991 | invalid flags. | |
| 1992 | 1992 | ||
| 1993 | + <a id="ERR_WORKER_OUT_OF_MEMORY"></a> | ||
| 1994 | + ### `ERR_WORKER_OUT_OF_MEMORY` | ||
| 1995 | + | ||
| 1996 | + The `Worker` instance terminated because it reached its memory limit. | ||
| 1997 | + | ||
| 1993 | 1998 | <a id="ERR_WORKER_PATH"></a> | |
| 1994 | 1999 | ### `ERR_WORKER_PATH` | |
| 1995 | 2000 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -157,6 +157,22 @@ console.log(receiveMessageOnPort(port2)); | |||
| 157 | 157 | When this function is used, no `'message'` event will be emitted and the | |
| 158 | 158 | `onmessage` listener will not be invoked. | |
| 159 | 159 | ||
| 160 | + ### `worker.resourceLimits` | ||
| 161 | + <!-- YAML | ||
| 162 | + added: REPLACEME | ||
| 163 | + --> | ||
| 164 | + | ||
| 165 | + * {Object|undefined} | ||
| 166 | + * `maxYoungGenerationSizeMb` {number} | ||
| 167 | + * `maxOldGenerationSizeMb` {number} | ||
| 168 | + * `codeRangeSizeMb` {number} | ||
| 169 | + | ||
| 170 | + Provides the set of JS engine resource constraints inside this Worker thread. | ||
| 171 | + If the `resourceLimits` option was passed to the [`Worker`][] constructor, | ||
| 172 | + this matches its values. | ||
| 173 | + | ||
| 174 | + If this is used in the main thread, its value is an empty object. | ||
| 175 | + | ||
| 160 | 176 | ## `worker.SHARE_ENV` | |
| 161 | 177 | <!-- YAML | |
| 162 | 178 | added: v11.14.0 | |
@@ -488,6 +504,13 @@ if (isMainThread) { | |||
| 488 | 504 | ``` | |
| 489 | 505 | ||
| 490 | 506 | ### `new Worker(filename[, options])` | |
| 507 | + <!-- YAML | ||
| 508 | + added: v10.5.0 | ||
| 509 | + changes: | ||
| 510 | + - version: REPLACEME | ||
| 511 | + pr-url: https://github.com/nodejs/node/pull/26628 | ||
| 512 | + description: The `resourceLimits` option was introduced. | ||
| 513 | + --> | ||
| 491 | 514 | ||
| 492 | 515 | * `filename` {string} The path to the Worker’s main script. Must be | |
| 493 | 516 | either an absolute path or a relative path (i.e. relative to the | |
@@ -519,6 +542,16 @@ if (isMainThread) { | |||
| 519 | 542 | occur as described in the [HTML structured clone algorithm][], and an error | |
| 520 | 543 | will be thrown if the object cannot be cloned (e.g. because it contains | |
| 521 | 544 | `function`s). | |
| 545 | + * `resourceLimits` {Object} An optional set of resource limits for the new | ||
| 546 | + JS engine instance. Reaching these limits will lead to termination of the | ||
| 547 | + `Worker` instance. These limits only affect the JS engine, and no external | ||
| 548 | + data, including no `ArrayBuffer`s. Even if these limits are set, the process | ||
| 549 | + may still abort if it encounters a global out-of-memory situation. | ||
| 550 | + * `maxOldGenerationSizeMb` {number} The maximum size of the main heap in MB. | ||
| 551 | + * `maxYoungGenerationSizeMb` {number} The maximum size of a heap space for | ||
| 552 | + recently created objects. | ||
| 553 | + * `codeRangeSizeMb` {number} The size of a pre-allocated memory range | ||
| 554 | + used for generated code. | ||
| 522 | 555 | ||
| 523 | 556 | ### Event: `'error'` | |
| 524 | 557 | <!-- YAML | |
@@ -583,6 +616,21 @@ Opposite of `unref()`, calling `ref()` on a previously `unref()`ed worker will | |||
| 583 | 616 | behavior). If the worker is `ref()`ed, calling `ref()` again will have | |
| 584 | 617 | no effect. | |
| 585 | 618 | ||
| 619 | + ### `worker.resourceLimits` | ||
| 620 | + <!-- YAML | ||
| 621 | + added: REPLACEME | ||
| 622 | + --> | ||
| 623 | + | ||
| 624 | + * {Object} | ||
| 625 | + * `maxYoungGenerationSizeMb` {number} | ||
| 626 | + * `maxOldGenerationSizeMb` {number} | ||
| 627 | + * `codeRangeSizeMb` {number} | ||
| 628 | + | ||
| 629 | + Provides the set of JS engine resource constraints for this Worker thread. | ||
| 630 | + If the `resourceLimits` option was passed to the [`Worker`][] constructor, | ||
| 631 | + this matches its values. | ||
| 632 | + | ||
| 633 | + If the worker has stopped, the return value is an empty object. | ||
| 586 | 634 | ### `worker.stderr` | |
| 587 | 635 | <!-- YAML | |
| 588 | 636 | added: v10.5.0 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1218,6 +1218,8 @@ E('ERR_VM_MODULE_STATUS', 'Module status %s', Error); | |||
| 1218 | 1218 | E('ERR_WORKER_INVALID_EXEC_ARGV', (errors) => | |
| 1219 | 1219 | `Initiated Worker with invalid execArgv flags: ${errors.join(', ')}`, | |
| 1220 | 1220 | Error); | |
| 1221 | + E('ERR_WORKER_OUT_OF_MEMORY', 'Worker terminated due to reaching memory limit', | ||
| 1222 | + Error); | ||
| 1221 | 1223 | E('ERR_WORKER_PATH', | |
| 1222 | 1224 | 'The worker script filename must be an absolute path or a relative ' + | |
| 1223 | 1225 | 'path starting with \'./\' or \'../\'. Received "%s"', | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,19 +2,20 @@ | |||
| 2 | 2 | ||
| 3 | 3 | /* global SharedArrayBuffer */ | |
| 4 | 4 | ||
| 5 | - const { Object } = primordials; | ||
| 5 | + const { Math, Object } = primordials; | ||
| 6 | 6 | ||
| 7 | 7 | const EventEmitter = require('events'); | |
| 8 | 8 | const assert = require('internal/assert'); | |
| 9 | 9 | const path = require('path'); | |
| 10 | 10 | ||
| 11 | + const errorCodes = require('internal/errors').codes; | ||
| 11 | 12 | const { | |
| 12 | 13 | ERR_WORKER_PATH, | |
| 13 | 14 | ERR_WORKER_UNSERIALIZABLE_ERROR, | |
| 14 | 15 | ERR_WORKER_UNSUPPORTED_EXTENSION, | |
| 15 | 16 | ERR_WORKER_INVALID_EXEC_ARGV, | |
| 16 | 17 | ERR_INVALID_ARG_TYPE, | |
| 17 | - } = require('internal/errors').codes; | ||
| 18 | + } = errorCodes; | ||
| 18 | 19 | const { validateString } = require('internal/validators'); | |
| 19 | 20 | const { getOptionValue } = require('internal/options'); | |
| 20 | 21 | ||
@@ -37,8 +38,13 @@ const { pathToFileURL } = require('url'); | |||
| 37 | 38 | const { | |
| 38 | 39 | ownsProcessState, | |
| 39 | 40 | isMainThread, | |
| 41 | + resourceLimits: resourceLimitsRaw, | ||
| 40 | 42 | threadId, | |
| 41 | 43 | Worker: WorkerImpl, | |
| 44 | + kMaxYoungGenerationSizeMb, | ||
| 45 | + kMaxOldGenerationSizeMb, | ||
| 46 | + kCodeRangeSizeMb, | ||
| 47 | + kTotalResourceLimitCount | ||
| 42 | 48 | } = internalBinding('worker'); | |
| 43 | 49 | ||
| 44 | 50 | const kHandle = Symbol('kHandle'); | |
@@ -102,7 +108,8 @@ class Worker extends EventEmitter { | |||
| 102 | 108 | ||
| 103 | 109 | const url = options.eval ? null : pathToFileURL(filename); | |
| 104 | 110 | // Set up the C++ handle for the worker, as well as some internal wiring. | |
| 105 | - this[kHandle] = new WorkerImpl(url, options.execArgv); | ||
| 111 | + this[kHandle] = new WorkerImpl(url, options.execArgv, | ||
| 112 | + parseResourceLimits(options.resourceLimits)); | ||
| 106 | 113 | if (this[kHandle].invalidExecArgv) { | |
| 107 | 114 | throw new ERR_WORKER_INVALID_EXEC_ARGV(this[kHandle].invalidExecArgv); | |
| 108 | 115 | } | |
@@ -113,7 +120,7 @@ class Worker extends EventEmitter { | |||
| 113 | 120 | } else if (env !== undefined) { | |
| 114 | 121 | this[kHandle].setEnvVars(env); | |
| 115 | 122 | } | |
| 116 | - this[kHandle].onexit = (code) => this[kOnExit](code); | ||
| 123 | + this[kHandle].onexit = (code, customErr) => this[kOnExit](code, customErr); | ||
| 117 | 124 | this[kPort] = this[kHandle].messagePort; | |
| 118 | 125 | this[kPort].on('message', (data) => this[kOnMessage](data)); | |
| 119 | 126 | this[kPort].start(); | |
@@ -157,11 +164,15 @@ class Worker extends EventEmitter { | |||
| 157 | 164 | this[kHandle].startThread(); | |
| 158 | 165 | } | |
| 159 | 166 | ||
| 160 | - [kOnExit](code) { | ||
| 167 | + [kOnExit](code, customErr) { | ||
| 161 | 168 | debug(`[${threadId}] hears end event for Worker ${this.threadId}`); | |
| 162 | 169 | drainMessagePort(this[kPublicPort]); | |
| 163 | 170 | drainMessagePort(this[kPort]); | |
| 164 | 171 | this[kDispose](); | |
| 172 | + if (customErr) { | ||
| 173 | + debug(`[${threadId}] failing with custom error ${customErr}`); | ||
| 174 | + this.emit('error', new errorCodes[customErr]()); | ||
| 175 | + } | ||
| 165 | 176 | this.emit('exit', code); | |
| 166 | 177 | this.removeAllListeners(); | |
| 167 | 178 | } | |
@@ -280,6 +291,12 @@ class Worker extends EventEmitter { | |||
| 280 | 291 | get stderr() { | |
| 281 | 292 | return this[kParentSideStdio].stderr; | |
| 282 | 293 | } | |
| 294 | + | ||
| 295 | + get resourceLimits() { | ||
| 296 | + if (this[kHandle] === null) return {}; | ||
| 297 | + | ||
| 298 | + return makeResourceLimits(this[kHandle].getResourceLimits()); | ||
| 299 | + } | ||
| 283 | 300 | } | |
| 284 | 301 | ||
| 285 | 302 | function pipeWithoutWarning(source, dest) { | |
@@ -294,10 +311,35 @@ function pipeWithoutWarning(source, dest) { | |||
| 294 | 311 | dest._maxListeners = destMaxListeners; | |
| 295 | 312 | } | |
| 296 | 313 | ||
| 314 | + const resourceLimitsArray = new Float64Array(kTotalResourceLimitCount); | ||
| 315 | + function parseResourceLimits(obj) { | ||
| 316 | + const ret = resourceLimitsArray; | ||
| 317 | + ret.fill(-1); | ||
| 318 | + if (typeof obj !== 'object' || obj === null) return ret; | ||
| 319 | + | ||
| 320 | + if (typeof obj.maxOldGenerationSizeMb === 'number') | ||
| 321 | + ret[kMaxOldGenerationSizeMb] = Math.max(obj.maxOldGenerationSizeMb, 2); | ||
| 322 | + if (typeof obj.maxYoungGenerationSizeMb === 'number') | ||
| 323 | + ret[kMaxYoungGenerationSizeMb] = obj.maxYoungGenerationSizeMb; | ||
| 324 | + if (typeof obj.codeRangeSizeMb === 'number') | ||
| 325 | + ret[kCodeRangeSizeMb] = obj.codeRangeSizeMb; | ||
| 326 | + return ret; | ||
| 327 | + } | ||
| 328 | + | ||
| 329 | + function makeResourceLimits(float64arr) { | ||
| 330 | + return { | ||
| 331 | + maxYoungGenerationSizeMb: float64arr[kMaxYoungGenerationSizeMb], | ||
| 332 | + maxOldGenerationSizeMb: float64arr[kMaxOldGenerationSizeMb], | ||
| 333 | + codeRangeSizeMb: float64arr[kCodeRangeSizeMb] | ||
| 334 | + }; | ||
| 335 | + } | ||
| 336 | + | ||
| 297 | 337 | module.exports = { | |
| 298 | 338 | ownsProcessState, | |
| 299 | 339 | isMainThread, | |
| 300 | 340 | SHARE_ENV, | |
| 341 | + resourceLimits: | ||
| 342 | + !isMainThread ? makeResourceLimits(resourceLimitsRaw) : {}, | ||
| 301 | 343 | threadId, | |
| 302 | 344 | Worker, | |
| 303 | 345 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,6 +3,7 @@ | |||
| 3 | 3 | const { | |
| 4 | 4 | isMainThread, | |
| 5 | 5 | SHARE_ENV, | |
| 6 | + resourceLimits, | ||
| 6 | 7 | threadId, | |
| 7 | 8 | Worker | |
| 8 | 9 | } = require('internal/worker'); | |
@@ -20,6 +21,7 @@ module.exports = { | |||
| 20 | 21 | MessageChannel, | |
| 21 | 22 | moveMessagePortToContext, | |
| 22 | 23 | receiveMessageOnPort, | |
| 24 | + resourceLimits, | ||
| 23 | 25 | threadId, | |
| 24 | 26 | SHARE_ENV, | |
| 25 | 27 | Worker, | |
| Back | FazBrowse Home | New Git URL |
0 commit comments