Skip to content

Commit a646a22

Browse files
debadree25targos
authored andcommittedMar 14, 2023
worker: add support for worker name in inspector and trace_events
Fixes: #41589 PR-URL: #46832 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
1 parent 5fdd3f4 commit a646a22

14 files changed

+144
-30
lines changed
 

‎doc/api/worker_threads.md

+7
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,10 @@ if (isMainThread) {
906906
<!-- YAML
907907
added: v10.5.0
908908
changes:
909+
- version: REPLACEME
910+
pr-url: https://github.com/nodejs/node/pull/46832
911+
description: Added support for a `name` option, which allows
912+
adding a name to worker title for debugging.
909913
- version: v14.9.0
910914
pr-url: https://github.com/nodejs/node/pull/34584
911915
description: The `filename` parameter can be a WHATWG `URL` object using
@@ -1004,6 +1008,9 @@ changes:
10041008
used for generated code.
10051009
* `stackSizeMb` {number} The default maximum stack size for the thread.
10061010
Small values may lead to unusable Worker instances. **Default:** `4`.
1011+
* `name` {string} An optional `name` to be appended to the worker title
1012+
for debuggin/identification purposes, making the final title as
1013+
`[worker ${id}] ${name}`. **Default:** `''`.
10071014

10081015
### Event: `'error'`
10091016

‎lib/internal/worker.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const {
1616
SafeArrayIterator,
1717
SafeMap,
1818
String,
19+
StringPrototypeTrim,
1920
Symbol,
2021
SymbolFor,
2122
TypedArrayPrototypeFill,
@@ -57,7 +58,7 @@ const {
5758
const { deserializeError } = require('internal/error_serdes');
5859
const { fileURLToPath, isURLInstance, pathToFileURL } = require('internal/url');
5960
const { kEmptyObject } = require('internal/util');
60-
const { validateArray } = require('internal/validators');
61+
const { validateArray, validateString } = require('internal/validators');
6162

6263
const {
6364
ownsProcessState,
@@ -188,12 +189,19 @@ class Worker extends EventEmitter {
188189
options.env);
189190
}
190191

192+
let name = '';
193+
if (options.name) {
194+
validateString(options.name, 'options.name');
195+
name = StringPrototypeTrim(options.name);
196+
}
197+
191198
// Set up the C++ handle for the worker, as well as some internal wiring.
192199
this[kHandle] = new WorkerImpl(url,
193200
env === process.env ? null : env,
194201
options.execArgv,
195202
parseResourceLimits(options.resourceLimits),
196-
!!(options.trackUnmanagedFds ?? true));
203+
!!(options.trackUnmanagedFds ?? true),
204+
name);
197205
if (this[kHandle].invalidExecArgv) {
198206
throw new ERR_WORKER_INVALID_EXEC_ARGV(this[kHandle].invalidExecArgv);
199207
}

‎src/api/environment.cc

+7-1
Original file line numberDiff line numberDiff line change
@@ -529,11 +529,17 @@ NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
529529
Environment* env,
530530
ThreadId thread_id,
531531
const char* url) {
532+
return GetInspectorParentHandle(env, thread_id, url, "");
533+
}
534+
535+
NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
536+
Environment* env, ThreadId thread_id, const char* url, const char* name) {
532537
CHECK_NOT_NULL(env);
538+
if (name == nullptr) name = "";
533539
CHECK_NE(thread_id.id, static_cast<uint64_t>(-1));
534540
#if HAVE_INSPECTOR
535541
return std::make_unique<InspectorParentHandleImpl>(
536-
env->inspector_agent()->GetParentHandle(thread_id.id, url));
542+
env->inspector_agent()->GetParentHandle(thread_id.id, url, name));
537543
#else
538544
return {};
539545
#endif

‎src/inspector/worker_inspector.cc

+14-9
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,20 @@ class WorkerStartedRequest : public Request {
1414
uint64_t id,
1515
const std::string& url,
1616
std::shared_ptr<node::inspector::MainThreadHandle> worker_thread,
17-
bool waiting)
17+
bool waiting,
18+
const std::string& name)
1819
: id_(id),
19-
info_(BuildWorkerTitle(id), url, worker_thread),
20+
info_(BuildWorkerTitle(id, name), url, worker_thread),
2021
waiting_(waiting) {}
2122
void Call(MainThreadInterface* thread) override {
2223
auto manager = thread->inspector_agent()->GetWorkerManager();
2324
manager->WorkerStarted(id_, info_, waiting_);
2425
}
2526

2627
private:
27-
static std::string BuildWorkerTitle(int id) {
28-
return "Worker " + std::to_string(id);
28+
static std::string BuildWorkerTitle(int id, const std::string& name) {
29+
return "[worker " + std::to_string(id) + "]" +
30+
(name == "" ? "" : " " + name);
2931
}
3032

3133
uint64_t id_;
@@ -57,11 +59,13 @@ ParentInspectorHandle::ParentInspectorHandle(
5759
uint64_t id,
5860
const std::string& url,
5961
std::shared_ptr<MainThreadHandle> parent_thread,
60-
bool wait_for_connect)
62+
bool wait_for_connect,
63+
const std::string& name)
6164
: id_(id),
6265
url_(url),
6366
parent_thread_(parent_thread),
64-
wait_(wait_for_connect) {}
67+
wait_(wait_for_connect),
68+
name_(name) {}
6569

6670
ParentInspectorHandle::~ParentInspectorHandle() {
6771
parent_thread_->Post(
@@ -71,7 +75,7 @@ ParentInspectorHandle::~ParentInspectorHandle() {
7175
void ParentInspectorHandle::WorkerStarted(
7276
std::shared_ptr<MainThreadHandle> worker_thread, bool waiting) {
7377
std::unique_ptr<Request> request(
74-
new WorkerStartedRequest(id_, url_, worker_thread, waiting));
78+
new WorkerStartedRequest(id_, url_, worker_thread, waiting, name_));
7579
parent_thread_->Post(std::move(request));
7680
}
7781

@@ -97,9 +101,10 @@ void WorkerManager::WorkerStarted(uint64_t session_id,
97101
}
98102

99103
std::unique_ptr<ParentInspectorHandle> WorkerManager::NewParentHandle(
100-
uint64_t thread_id, const std::string& url) {
104+
uint64_t thread_id, const std::string& url, const std::string& name) {
101105
bool wait = !delegates_waiting_on_start_.empty();
102-
return std::make_unique<ParentInspectorHandle>(thread_id, url, thread_, wait);
106+
return std::make_unique<ParentInspectorHandle>(
107+
thread_id, url, thread_, wait, name);
103108
}
104109

105110
void WorkerManager::RemoveAttachDelegate(int id) {

‎src/inspector/worker_inspector.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,13 @@ class ParentInspectorHandle {
5656
ParentInspectorHandle(uint64_t id,
5757
const std::string& url,
5858
std::shared_ptr<MainThreadHandle> parent_thread,
59-
bool wait_for_connect);
59+
bool wait_for_connect,
60+
const std::string& name);
6061
~ParentInspectorHandle();
6162
std::unique_ptr<ParentInspectorHandle> NewParentInspectorHandle(
62-
uint64_t thread_id, const std::string& url) {
63-
return std::make_unique<ParentInspectorHandle>(thread_id,
64-
url,
65-
parent_thread_,
66-
wait_);
63+
uint64_t thread_id, const std::string& url, const std::string& name) {
64+
return std::make_unique<ParentInspectorHandle>(
65+
thread_id, url, parent_thread_, wait_, name);
6766
}
6867
void WorkerStarted(std::shared_ptr<MainThreadHandle> worker_thread,
6968
bool waiting);
@@ -80,6 +79,7 @@ class ParentInspectorHandle {
8079
std::string url_;
8180
std::shared_ptr<MainThreadHandle> parent_thread_;
8281
bool wait_;
82+
std::string name_;
8383
};
8484

8585
class WorkerManager : public std::enable_shared_from_this<WorkerManager> {
@@ -88,7 +88,7 @@ class WorkerManager : public std::enable_shared_from_this<WorkerManager> {
8888
: thread_(thread) {}
8989

9090
std::unique_ptr<ParentInspectorHandle> NewParentHandle(
91-
uint64_t thread_id, const std::string& url);
91+
uint64_t thread_id, const std::string& url, const std::string& name);
9292
void WorkerStarted(uint64_t session_id, const WorkerInfo& info, bool waiting);
9393
void WorkerFinished(uint64_t session_id);
9494
std::unique_ptr<WorkerManagerEventHandle> SetAutoAttach(

‎src/inspector_agent.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -952,17 +952,17 @@ void Agent::SetParentHandle(
952952
}
953953

954954
std::unique_ptr<ParentInspectorHandle> Agent::GetParentHandle(
955-
uint64_t thread_id, const std::string& url) {
955+
uint64_t thread_id, const std::string& url, const std::string& name) {
956956
if (!parent_env_->should_create_inspector() && !client_) {
957957
ThrowUninitializedInspectorError(parent_env_);
958958
return std::unique_ptr<ParentInspectorHandle>{};
959959
}
960960

961961
CHECK_NOT_NULL(client_);
962962
if (!parent_handle_) {
963-
return client_->getWorkerManager()->NewParentHandle(thread_id, url);
963+
return client_->getWorkerManager()->NewParentHandle(thread_id, url, name);
964964
} else {
965-
return parent_handle_->NewParentInspectorHandle(thread_id, url);
965+
return parent_handle_->NewParentInspectorHandle(thread_id, url, name);
966966
}
967967
}
968968

‎src/inspector_agent.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class Agent {
8282

8383
void SetParentHandle(std::unique_ptr<ParentInspectorHandle> parent_handle);
8484
std::unique_ptr<ParentInspectorHandle> GetParentHandle(
85-
uint64_t thread_id, const std::string& url);
85+
uint64_t thread_id, const std::string& url, const std::string& name);
8686

8787
// Called to create inspector sessions that can be used from the same thread.
8888
// The inspector responds by using the delegate to send messages back.

‎src/node.h

+6
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,12 @@ NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
696696
ThreadId child_thread_id,
697697
const char* child_url);
698698

699+
NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
700+
Environment* parent_env,
701+
ThreadId child_thread_id,
702+
const char* child_url,
703+
const char* name);
704+
699705
struct StartExecutionCallbackInfo {
700706
v8::Local<v8::Object> process_object;
701707
v8::Local<v8::Function> native_require;

‎src/node_worker.cc

+15-6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ constexpr double kMB = 1024 * 1024;
4949
Worker::Worker(Environment* env,
5050
Local<Object> wrap,
5151
const std::string& url,
52+
const std::string& name,
5253
std::shared_ptr<PerIsolateOptions> per_isolate_opts,
5354
std::vector<std::string>&& exec_argv,
5455
std::shared_ptr<KVStore> env_vars,
@@ -58,6 +59,7 @@ Worker::Worker(Environment* env,
5859
exec_argv_(exec_argv),
5960
platform_(env->isolate_data()->platform()),
6061
thread_id_(AllocateEnvironmentThreadId()),
62+
name_(name),
6163
env_vars_(env_vars),
6264
snapshot_data_(snapshot_data) {
6365
Debug(this, "Creating new worker instance with thread id %llu",
@@ -82,8 +84,8 @@ Worker::Worker(Environment* env,
8284
Number::New(env->isolate(), static_cast<double>(thread_id_.id)))
8385
.Check();
8486

85-
inspector_parent_handle_ = GetInspectorParentHandle(
86-
env, thread_id_, url.c_str());
87+
inspector_parent_handle_ =
88+
GetInspectorParentHandle(env, thread_id_, url.c_str(), name.c_str());
8789

8890
argv_ = std::vector<std::string>{env->argv()[0]};
8991
// Mark this Worker object as weak until we actually start the thread.
@@ -264,11 +266,10 @@ size_t Worker::NearHeapLimit(void* data, size_t current_heap_limit,
264266
}
265267

266268
void Worker::Run() {
267-
std::string name = "WorkerThread ";
268-
name += std::to_string(thread_id_.id);
269+
std::string trace_name = "[worker " + std::to_string(thread_id_.id) + "]" +
270+
(name_ == "" ? "" : " " + name_);
269271
TRACE_EVENT_METADATA1(
270-
"__metadata", "thread_name", "name",
271-
TRACE_STR_COPY(name.c_str()));
272+
"__metadata", "thread_name", "name", TRACE_STR_COPY(trace_name.c_str()));
272273
CHECK_NOT_NULL(platform_);
273274

274275
Debug(this, "Creating isolate for worker with id %llu", thread_id_.id);
@@ -467,6 +468,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
467468
}
468469

469470
std::string url;
471+
std::string name;
470472
std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr;
471473
std::shared_ptr<KVStore> env_vars = nullptr;
472474

@@ -479,6 +481,12 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
479481
url.append(value.out(), value.length());
480482
}
481483

484+
if (!args[5]->IsNullOrUndefined()) {
485+
Utf8Value value(
486+
isolate, args[5]->ToString(env->context()).FromMaybe(Local<String>()));
487+
name.append(value.out(), value.length());
488+
}
489+
482490
if (args[1]->IsNull()) {
483491
// Means worker.env = { ...process.env }.
484492
env_vars = env->env_vars()->Clone(isolate);
@@ -589,6 +597,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
589597
Worker* worker = new Worker(env,
590598
args.This(),
591599
url,
600+
name,
592601
per_isolate_opts,
593602
std::move(exec_argv_out),
594603
env_vars,

‎src/node_worker.h

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Worker : public AsyncWrap {
3030
Worker(Environment* env,
3131
v8::Local<v8::Object> wrap,
3232
const std::string& url,
33+
const std::string& name,
3334
std::shared_ptr<PerIsolateOptions> per_isolate_opts,
3435
std::vector<std::string>&& exec_argv,
3536
std::shared_ptr<KVStore> env_vars,
@@ -99,6 +100,8 @@ class Worker : public AsyncWrap {
99100
ExitCode exit_code_ = ExitCode::kNoFailure;
100101
ThreadId thread_id_;
101102
uintptr_t stack_base_ = 0;
103+
// Optional name used for debugging in inspector and trace events.
104+
std::string name_;
102105

103106
// Custom resource constraints:
104107
double resource_limits_[kTotalResourceLimitCount];

‎test/fixtures/worker-name.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const { Session } = require('inspector');
2+
const { parentPort } = require('worker_threads');
3+
4+
const session = new Session();
5+
6+
parentPort.once('message', () => {}); // Prevent the worker from exiting.
7+
8+
session.connectToMainThread();
9+
10+
session.on(
11+
'NodeWorker.attachedToWorker',
12+
({ params: { workerInfo } }) => {
13+
// send the worker title to the main thread
14+
parentPort.postMessage(workerInfo.title);
15+
}
16+
);
17+
session.post('NodeWorker.enable', { waitForDebuggerOnStart: false });
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const cp = require('child_process');
5+
const fs = require('fs');
6+
const { isMainThread } = require('worker_threads');
7+
8+
if (isMainThread) {
9+
const CODE = 'const { Worker } = require(\'worker_threads\'); ' +
10+
`new Worker('${__filename.replace(/\\/g, '/')}', { name: 'foo' })`;
11+
const FILE_NAME = 'node_trace.1.log';
12+
const tmpdir = require('../common/tmpdir');
13+
tmpdir.refresh();
14+
process.chdir(tmpdir.path);
15+
16+
const proc = cp.spawn(process.execPath,
17+
[ '--trace-event-categories', 'node',
18+
'-e', CODE ]);
19+
proc.once('exit', common.mustCall(() => {
20+
assert(fs.existsSync(FILE_NAME));
21+
fs.readFile(FILE_NAME, common.mustCall((err, data) => {
22+
const traces = JSON.parse(data.toString()).traceEvents;
23+
assert(traces.length > 0);
24+
assert(traces.some((trace) =>
25+
trace.cat === '__metadata' && trace.name === 'thread_name' &&
26+
trace.args.name === '[worker 1] foo'));
27+
}));
28+
}));
29+
} else {
30+
// Do nothing here.
31+
}

‎test/parallel/test-trace-events-worker-metadata.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ if (isMainThread) {
2323
assert(traces.length > 0);
2424
assert(traces.some((trace) =>
2525
trace.cat === '__metadata' && trace.name === 'thread_name' &&
26-
trace.args.name === 'WorkerThread 1'));
26+
trace.args.name === '[worker 1]'));
2727
}));
2828
}));
2929
} else {

‎test/parallel/test-worker-name.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fixtures = require('../common/fixtures');
5+
6+
common.skipIfInspectorDisabled();
7+
common.skipIfWorker(); // This test requires both main and worker threads.
8+
9+
const assert = require('assert');
10+
const { Worker, isMainThread } = require('worker_threads');
11+
12+
if (isMainThread) {
13+
const name = 'Hello Thread';
14+
const expectedTitle = `[worker 1] ${name}`;
15+
const worker = new Worker(fixtures.path('worker-name.js'), {
16+
name,
17+
});
18+
worker.once('message', common.mustCall((message) => {
19+
assert.strictEqual(message, expectedTitle);
20+
worker.postMessage('done');
21+
}));
22+
}

0 commit comments

Comments
 (0)