Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f2389eb

Browse filesBrowse files
HarshithaKPcodebytere
authored andcommitted
worker: emit runtime error on loop creation failure
Instead of hard asserting throw a runtime error, that is more consumable. Fixes: #31614 PR-URL: #31621 Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent a86cb0e commit f2389eb
Copy full SHA for f2389eb

File tree

Expand file treeCollapse file tree

6 files changed

+50
-17
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

6 files changed

+50
-17
lines changed
Open diff view settings
Collapse file

‎doc/api/errors.md‎

Copy file name to clipboardExpand all lines: doc/api/errors.md
+5Lines changed: 5 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -2066,6 +2066,11 @@ meaning of the error depends on the specific function.
20662066

20672067
The WASI instance has already started.
20682068

2069+
<a id="ERR_WORKER_INIT_FAILED"></a>
2070+
### `ERR_WORKER_INIT_FAILED`
2071+
2072+
The `Worker` initialization failed.
2073+
20692074
<a id="ERR_WORKER_INVALID_EXEC_ARGV"></a>
20702075
### `ERR_WORKER_INVALID_EXEC_ARGV`
20712076

Collapse file

‎lib/internal/errors.js‎

Copy file name to clipboardExpand all lines: lib/internal/errors.js
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,12 +1381,13 @@ E('ERR_VM_MODULE_NOT_MODULE',
13811381
'Provided module is not an instance of Module', Error);
13821382
E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
13831383
E('ERR_WASI_ALREADY_STARTED', 'WASI instance has already started', Error);
1384+
E('ERR_WORKER_INIT_FAILED', 'Worker initialization failure: %s', Error);
13841385
E('ERR_WORKER_INVALID_EXEC_ARGV', (errors, msg = 'invalid execArgv flags') =>
13851386
`Initiated Worker with ${msg}: ${errors.join(', ')}`,
13861387
Error);
13871388
E('ERR_WORKER_NOT_RUNNING', 'Worker instance not running', Error);
1388-
E('ERR_WORKER_OUT_OF_MEMORY', 'Worker terminated due to reaching memory limit',
1389-
Error);
1389+
E('ERR_WORKER_OUT_OF_MEMORY',
1390+
'Worker terminated due to reaching memory limit: %s', Error);
13901391
E('ERR_WORKER_PATH',
13911392
'The worker script filename must be an absolute path or a relative ' +
13921393
'path starting with \'./\' or \'../\'. Received "%s"',
Collapse file

‎lib/internal/worker.js‎

Copy file name to clipboardExpand all lines: lib/internal/worker.js
+9-4Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const {
2525
ERR_WORKER_UNSUPPORTED_EXTENSION,
2626
ERR_WORKER_INVALID_EXEC_ARGV,
2727
ERR_INVALID_ARG_TYPE,
28+
// eslint-disable-next-line no-unused-vars
29+
ERR_WORKER_INIT_FAILED,
2830
} = errorCodes;
2931
const { validateString } = require('internal/validators');
3032
const { getOptionValue } = require('internal/options');
@@ -136,7 +138,9 @@ class Worker extends EventEmitter {
136138
throw new ERR_WORKER_INVALID_EXEC_ARGV(
137139
this[kHandle].invalidNodeOptions, 'invalid NODE_OPTIONS env variable');
138140
}
139-
this[kHandle].onexit = (code, customErr) => this[kOnExit](code, customErr);
141+
this[kHandle].onexit = (code, customErr, customErrReason) => {
142+
this[kOnExit](code, customErr, customErrReason);
143+
};
140144
this[kPort] = this[kHandle].messagePort;
141145
this[kPort].on('message', (data) => this[kOnMessage](data));
142146
this[kPort].start();
@@ -181,14 +185,15 @@ class Worker extends EventEmitter {
181185
this[kHandle].startThread();
182186
}
183187

184-
[kOnExit](code, customErr) {
188+
[kOnExit](code, customErr, customErrReason) {
185189
debug(`[${threadId}] hears end event for Worker ${this.threadId}`);
186190
drainMessagePort(this[kPublicPort]);
187191
drainMessagePort(this[kPort]);
188192
this[kDispose]();
189193
if (customErr) {
190-
debug(`[${threadId}] failing with custom error ${customErr}`);
191-
this.emit('error', new errorCodes[customErr]());
194+
debug(`[${threadId}] failing with custom error ${customErr} \
195+
and with reason {customErrReason}`);
196+
this.emit('error', new errorCodes[customErr](customErrReason));
192197
}
193198
this.emit('exit', code);
194199
this.removeAllListeners();
Collapse file

‎src/node_worker.cc‎

Copy file name to clipboardExpand all lines: src/node_worker.cc
+29-10Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,16 @@ class WorkerThreadData {
133133
public:
134134
explicit WorkerThreadData(Worker* w)
135135
: w_(w) {
136-
CHECK_EQ(uv_loop_init(&loop_), 0);
136+
int ret = uv_loop_init(&loop_);
137+
if (ret != 0) {
138+
char err_buf[128];
139+
uv_err_name_r(ret, err_buf, sizeof(err_buf));
140+
w->custom_error_ = "ERR_WORKER_INIT_FAILED";
141+
w->custom_error_str_ = err_buf;
142+
w->loop_init_failed_ = true;
143+
w->stopped_ = true;
144+
return;
145+
}
137146

138147
std::shared_ptr<ArrayBufferAllocator> allocator =
139148
ArrayBufferAllocator::Create();
@@ -146,6 +155,8 @@ class WorkerThreadData {
146155
Isolate* isolate = Isolate::Allocate();
147156
if (isolate == nullptr) {
148157
w->custom_error_ = "ERR_WORKER_OUT_OF_MEMORY";
158+
w->custom_error_str_ = "Failed to create new Isolate";
159+
w->stopped_ = true;
149160
return;
150161
}
151162

@@ -204,11 +215,14 @@ class WorkerThreadData {
204215
isolate->Dispose();
205216

206217
// Wait until the platform has cleaned up all relevant resources.
207-
while (!platform_finished)
218+
while (!platform_finished) {
219+
CHECK(!w_->loop_init_failed_);
208220
uv_run(&loop_, UV_RUN_ONCE);
221+
}
222+
}
223+
if (!w_->loop_init_failed_) {
224+
CheckedUvLoopClose(&loop_);
209225
}
210-
211-
CheckedUvLoopClose(&loop_);
212226
}
213227

214228
private:
@@ -223,6 +237,7 @@ size_t Worker::NearHeapLimit(void* data, size_t current_heap_limit,
223237
size_t initial_heap_limit) {
224238
Worker* worker = static_cast<Worker*>(data);
225239
worker->custom_error_ = "ERR_WORKER_OUT_OF_MEMORY";
240+
worker->custom_error_str_ = "JS heap out of memory";
226241
worker->Exit(1);
227242
// Give the current GC some extra leeway to let it finish rather than
228243
// crash hard. We are not going to perform further allocations anyway.
@@ -242,6 +257,7 @@ void Worker::Run() {
242257

243258
WorkerThreadData data(this);
244259
if (isolate_ == nullptr) return;
260+
CHECK(!data.w_->loop_init_failed_);
245261

246262
Debug(this, "Starting worker with id %llu", thread_id_);
247263
{
@@ -287,9 +303,8 @@ void Worker::Run() {
287303
TryCatch try_catch(isolate_);
288304
context = NewContext(isolate_);
289305
if (context.IsEmpty()) {
290-
// TODO(addaleax): Inform the target about the actual underlying
291-
// failure.
292306
custom_error_ = "ERR_WORKER_OUT_OF_MEMORY";
307+
custom_error_str_ = "Failed to create new Context";
293308
return;
294309
}
295310
}
@@ -417,10 +432,14 @@ void Worker::JoinThread() {
417432
Undefined(env()->isolate())).Check();
418433

419434
Local<Value> args[] = {
420-
Integer::New(env()->isolate(), exit_code_),
421-
custom_error_ != nullptr ?
422-
OneByteString(env()->isolate(), custom_error_).As<Value>() :
423-
Null(env()->isolate()).As<Value>(),
435+
Integer::New(env()->isolate(), exit_code_),
436+
custom_error_ != nullptr
437+
? OneByteString(env()->isolate(), custom_error_).As<Value>()
438+
: Null(env()->isolate()).As<Value>(),
439+
!custom_error_str_.empty()
440+
? OneByteString(env()->isolate(), custom_error_str_.c_str())
441+
.As<Value>()
442+
: Null(env()->isolate()).As<Value>(),
424443
};
425444

426445
MakeCallback(env()->onexit_string(), arraysize(args), args);
Collapse file

‎src/node_worker.h‎

Copy file name to clipboardExpand all lines: src/node_worker.h
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ class Worker : public AsyncWrap {
8585

8686
bool thread_joined_ = true;
8787
const char* custom_error_ = nullptr;
88+
std::string custom_error_str_;
89+
bool loop_init_failed_ = false;
8890
int exit_code_ = 0;
8991
uint64_t thread_id_ = -1;
9092
uintptr_t stack_base_ = 0;
Collapse file

‎test/parallel/test-worker-resource-limits.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-worker-resource-limits.js
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ if (!process.env.HAS_STARTED_WORKER) {
2525
}));
2626
w.on('error', common.expectsError({
2727
code: 'ERR_WORKER_OUT_OF_MEMORY',
28-
message: 'Worker terminated due to reaching memory limit'
28+
message: 'Worker terminated due to reaching memory limit: ' +
29+
'JS heap out of memory'
2930
}));
3031
return;
3132
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.