Skip to content

Commit f7423bd

Browse files
debadree25danielleadams
authored andcommitted
worker: add support for worker name in inspector and trace_events
Fixes: #41589 PR-URL: #46832 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Darshan Sen <[email protected]> Reviewed-By: Gireesh Punathil <[email protected]>
1 parent 09c5e6a commit f7423bd

14 files changed

+144
-30
lines changed

doc/api/worker_threads.md

+7
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,10 @@ if (isMainThread) {
900900
<!-- YAML
901901
added: v10.5.0
902902
changes:
903+
- version: REPLACEME
904+
pr-url: https://github.com/nodejs/node/pull/46832
905+
description: Added support for a `name` option, which allows
906+
adding a name to worker title for debugging.
903907
- version: v14.9.0
904908
pr-url: https://github.com/nodejs/node/pull/34584
905909
description: The `filename` parameter can be a WHATWG `URL` object using
@@ -998,6 +1002,9 @@ changes:
9981002
used for generated code.
9991003
* `stackSizeMb` {number} The default maximum stack size for the thread.
10001004
Small values may lead to unusable Worker instances. **Default:** `4`.
1005+
* `name` {string} An optional `name` to be appended to the worker title
1006+
for debuggin/identification purposes, making the final title as
1007+
`[worker ${id}] ${name}`. **Default:** `''`.
10011008

10021009
### Event: `'error'`
10031010

lib/internal/worker.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const {
1717
SafeArrayIterator,
1818
SafeMap,
1919
String,
20+
StringPrototypeTrim,
2021
Symbol,
2122
SymbolFor,
2223
TypedArrayPrototypeFill,
@@ -56,7 +57,7 @@ const {
5657
const { deserializeError } = require('internal/error_serdes');
5758
const { fileURLToPath, isURLInstance, pathToFileURL } = require('internal/url');
5859
const { kEmptyObject } = require('internal/util');
59-
const { validateArray } = require('internal/validators');
60+
const { validateArray, validateString } = require('internal/validators');
6061

6162
const {
6263
ownsProcessState,
@@ -184,12 +185,19 @@ class Worker extends EventEmitter {
184185
options.env);
185186
}
186187

188+
let name = '';
189+
if (options.name) {
190+
validateString(options.name, 'options.name');
191+
name = StringPrototypeTrim(options.name);
192+
}
193+
187194
// Set up the C++ handle for the worker, as well as some internal wiring.
188195
this[kHandle] = new WorkerImpl(url,
189196
env === process.env ? null : env,
190197
options.execArgv,
191198
parseResourceLimits(options.resourceLimits),
192-
!!(options.trackUnmanagedFds ?? true));
199+
!!(options.trackUnmanagedFds ?? true),
200+
name);
193201
if (this[kHandle].invalidExecArgv) {
194202
throw new ERR_WORKER_INVALID_EXEC_ARGV(this[kHandle].invalidExecArgv);
195203
}

src/api/environment.cc

+7-1
Original file line numberDiff line numberDiff line change
@@ -453,11 +453,17 @@ NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
453453
Environment* env,
454454
ThreadId thread_id,
455455
const char* url) {
456+
return GetInspectorParentHandle(env, thread_id, url, "");
457+
}
458+
459+
NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
460+
Environment* env, ThreadId thread_id, const char* url, const char* name) {
456461
CHECK_NOT_NULL(env);
462+
if (name == nullptr) name = "";
457463
CHECK_NE(thread_id.id, static_cast<uint64_t>(-1));
458464
#if HAVE_INSPECTOR
459465
return std::make_unique<InspectorParentHandleImpl>(
460-
env->inspector_agent()->GetParentHandle(thread_id.id, url));
466+
env->inspector_agent()->GetParentHandle(thread_id.id, url, name));
461467
#else
462468
return {};
463469
#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
@@ -948,17 +948,17 @@ void Agent::SetParentHandle(
948948
}
949949

950950
std::unique_ptr<ParentInspectorHandle> Agent::GetParentHandle(
951-
uint64_t thread_id, const std::string& url) {
951+
uint64_t thread_id, const std::string& url, const std::string& name) {
952952
if (!parent_env_->should_create_inspector() && !client_) {
953953
ThrowUninitializedInspectorError(parent_env_);
954954
return std::unique_ptr<ParentInspectorHandle>{};
955955
}
956956

957957
CHECK_NOT_NULL(client_);
958958
if (!parent_handle_) {
959-
return client_->getWorkerManager()->NewParentHandle(thread_id, url);
959+
return client_->getWorkerManager()->NewParentHandle(thread_id, url, name);
960960
} else {
961-
return parent_handle_->NewParentInspectorHandle(thread_id, url);
961+
return parent_handle_->NewParentInspectorHandle(thread_id, url, name);
962962
}
963963
}
964964

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
@@ -590,6 +590,12 @@ NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
590590
ThreadId child_thread_id,
591591
const char* child_url);
592592

593+
NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
594+
Environment* parent_env,
595+
ThreadId child_thread_id,
596+
const char* child_url,
597+
const char* name);
598+
593599
struct StartExecutionCallbackInfo {
594600
v8::Local<v8::Object> process_object;
595601
v8::Local<v8::Function> native_require;

src/node_worker.cc

+15-6
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ constexpr double kMB = 1024 * 1024;
4848
Worker::Worker(Environment* env,
4949
Local<Object> wrap,
5050
const std::string& url,
51+
const std::string& name,
5152
std::shared_ptr<PerIsolateOptions> per_isolate_opts,
5253
std::vector<std::string>&& exec_argv,
5354
std::shared_ptr<KVStore> env_vars,
@@ -57,6 +58,7 @@ Worker::Worker(Environment* env,
5758
exec_argv_(exec_argv),
5859
platform_(env->isolate_data()->platform()),
5960
thread_id_(AllocateEnvironmentThreadId()),
61+
name_(name),
6062
env_vars_(env_vars),
6163
snapshot_data_(snapshot_data) {
6264
Debug(this, "Creating new worker instance with thread id %llu",
@@ -81,8 +83,8 @@ Worker::Worker(Environment* env,
8183
Number::New(env->isolate(), static_cast<double>(thread_id_.id)))
8284
.Check();
8385

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

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

258260
void Worker::Run() {
259-
std::string name = "WorkerThread ";
260-
name += std::to_string(thread_id_.id);
261+
std::string trace_name = "[worker " + std::to_string(thread_id_.id) + "]" +
262+
(name_ == "" ? "" : " " + name_);
261263
TRACE_EVENT_METADATA1(
262-
"__metadata", "thread_name", "name",
263-
TRACE_STR_COPY(name.c_str()));
264+
"__metadata", "thread_name", "name", TRACE_STR_COPY(trace_name.c_str()));
264265
CHECK_NOT_NULL(platform_);
265266

266267
Debug(this, "Creating isolate for worker with id %llu", thread_id_.id);
@@ -454,6 +455,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
454455
}
455456

456457
std::string url;
458+
std::string name;
457459
std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr;
458460
std::shared_ptr<KVStore> env_vars = nullptr;
459461

@@ -466,6 +468,12 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
466468
url.append(value.out(), value.length());
467469
}
468470

471+
if (!args[5]->IsNullOrUndefined()) {
472+
Utf8Value value(
473+
isolate, args[5]->ToString(env->context()).FromMaybe(Local<String>()));
474+
name.append(value.out(), value.length());
475+
}
476+
469477
if (args[1]->IsNull()) {
470478
// Means worker.env = { ...process.env }.
471479
env_vars = env->env_vars()->Clone(isolate);
@@ -579,6 +587,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
579587
Worker* worker = new Worker(env,
580588
args.This(),
581589
url,
590+
name,
582591
per_isolate_opts,
583592
std::move(exec_argv_out),
584593
env_vars,

src/node_worker.h

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Worker : public AsyncWrap {
2929
Worker(Environment* env,
3030
v8::Local<v8::Object> wrap,
3131
const std::string& url,
32+
const std::string& name,
3233
std::shared_ptr<PerIsolateOptions> per_isolate_opts,
3334
std::vector<std::string>&& exec_argv,
3435
std::shared_ptr<KVStore> env_vars,
@@ -98,6 +99,8 @@ class Worker : public AsyncWrap {
9899
int exit_code_ = 0;
99100
ThreadId thread_id_;
100101
uintptr_t stack_base_ = 0;
102+
// Optional name used for debugging in inspector and trace events.
103+
std::string name_;
101104

102105
// Custom resource constraints:
103106
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)