worker: add name for worker

PR-URL: https://github.com/nodejs/node/pull/59213
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
theanarkh 2025-08-05 21:45:41 +08:00 committed by GitHub
parent a4ce69e05f
commit 3090def635
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 118 additions and 5 deletions

View file

@ -721,6 +721,17 @@ An integer identifier for the current thread. On the corresponding worker object
(if there is any), it is available as [`worker.threadId`][].
This value is unique for each [`Worker`][] instance inside a single process.
## `worker.threadName`
<!-- YAML
added: REPLACEME
-->
* {string|null}
A string identifier for the current thread or null if the thread is not running.
On the corresponding worker object (if there is any), it is available as [`worker.threadName`][].
## `worker.workerData`
<!-- YAML
@ -2015,6 +2026,17 @@ An integer identifier for the referenced thread. Inside the worker thread,
it is available as [`require('node:worker_threads').threadId`][].
This value is unique for each `Worker` instance inside a single process.
### `worker.threadName`
<!-- YAML
added: REPLACEME
-->
* {string|null}
A string identifier for the referenced thread or null if the thread is not running.
Inside the worker thread, it is available as [`require('node:worker_threads').threadName`][].
### `worker.unref()`
<!-- YAML
@ -2145,6 +2167,7 @@ thread spawned will spawn another until the application crashes.
[`require('node:worker_threads').parentPort.postMessage()`]: #workerpostmessagevalue-transferlist
[`require('node:worker_threads').parentPort`]: #workerparentport
[`require('node:worker_threads').threadId`]: #workerthreadid
[`require('node:worker_threads').threadName`]: #workerthreadname
[`require('node:worker_threads').workerData`]: #workerworkerdata
[`trace_events`]: tracing.md
[`v8.getHeapSnapshot()`]: v8.md#v8getheapsnapshotoptions
@ -2155,6 +2178,7 @@ thread spawned will spawn another until the application crashes.
[`worker.postMessage()`]: #workerpostmessagevalue-transferlist
[`worker.terminate()`]: #workerterminate
[`worker.threadId`]: #workerthreadid_1
[`worker.threadName`]: #workerthreadname_1
[async-resource-worker-pool]: async_context.md#using-asyncresource-for-a-worker-thread-pool
[browser `LockManager`]: https://developer.mozilla.org/en-US/docs/Web/API/LockManager
[browser `MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort

View file

@ -73,6 +73,7 @@ const {
isInternalThread,
resourceLimits: resourceLimitsRaw,
threadId,
threadName,
Worker: WorkerImpl,
kMaxYoungGenerationSizeMb,
kMaxOldGenerationSizeMb,
@ -425,6 +426,12 @@ class Worker extends EventEmitter {
return this[kHandle].threadId;
}
get threadName() {
if (this[kHandle] === null) return null;
return this[kHandle].threadName;
}
get stdin() {
return this[kParentSideStdio].stdin;
}
@ -589,6 +596,7 @@ module.exports = {
getEnvironmentData,
assignEnvironmentData,
threadId,
threadName,
InternalWorker,
Worker,
};

View file

@ -8,6 +8,7 @@ const {
setEnvironmentData,
getEnvironmentData,
threadId,
threadName,
Worker,
} = require('internal/worker');
@ -44,6 +45,7 @@ module.exports = {
resourceLimits,
postMessageToThread,
threadId,
threadName,
SHARE_ENV,
Worker,
parentPort: null,

View file

@ -414,6 +414,25 @@ Environment* CreateEnvironment(
EnvironmentFlags::Flags flags,
ThreadId thread_id,
std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
return CreateEnvironment(isolate_data,
context,
args,
exec_args,
flags,
thread_id,
std::move(inspector_parent_handle),
{});
}
Environment* CreateEnvironment(
IsolateData* isolate_data,
Local<Context> context,
const std::vector<std::string>& args,
const std::vector<std::string>& exec_args,
EnvironmentFlags::Flags flags,
ThreadId thread_id,
std::unique_ptr<InspectorParentHandle> inspector_parent_handle,
std::string_view thread_name) {
Isolate* isolate = isolate_data->isolate();
Isolate::Scope isolate_scope(isolate);
@ -434,7 +453,8 @@ Environment* CreateEnvironment(
exec_args,
env_snapshot_info,
flags,
thread_id);
thread_id,
thread_name);
CHECK_NOT_NULL(env);
if (use_snapshot) {

View file

@ -695,6 +695,10 @@ inline uint64_t Environment::thread_id() const {
return thread_id_;
}
inline std::string_view Environment::thread_name() const {
return thread_name_;
}
inline worker::Worker* Environment::worker_context() const {
return isolate_data()->worker_context();
}

View file

@ -784,7 +784,8 @@ Environment::Environment(IsolateData* isolate_data,
const std::vector<std::string>& exec_args,
const EnvSerializeInfo* env_info,
EnvironmentFlags::Flags flags,
ThreadId thread_id)
ThreadId thread_id,
std::string_view thread_name)
: isolate_(isolate),
external_memory_accounter_(new ExternalMemoryAccounter()),
isolate_data_(isolate_data),
@ -811,7 +812,8 @@ Environment::Environment(IsolateData* isolate_data,
flags_(flags),
thread_id_(thread_id.id == static_cast<uint64_t>(-1)
? AllocateEnvironmentThreadId().id
: thread_id.id) {
: thread_id.id),
thread_name_(thread_name) {
if (!is_main_thread()) {
// If this is a Worker thread, we can always safely use the parent's
// Isolate's code cache because of the shared read-only heap.

View file

@ -660,7 +660,8 @@ class Environment final : public MemoryRetainer {
const std::vector<std::string>& exec_args,
const EnvSerializeInfo* env_info,
EnvironmentFlags::Flags flags,
ThreadId thread_id);
ThreadId thread_id,
std::string_view thread_name = "");
void InitializeMainContext(v8::Local<v8::Context> context,
const EnvSerializeInfo* env_info);
~Environment() override;
@ -807,6 +808,7 @@ class Environment final : public MemoryRetainer {
inline bool should_start_debug_signal_handler() const;
inline bool no_browser_globals() const;
inline uint64_t thread_id() const;
inline std::string_view thread_name() const;
inline worker::Worker* worker_context() const;
Environment* worker_parent_env() const;
inline void add_sub_worker_context(worker::Worker* context);
@ -1172,6 +1174,7 @@ class Environment final : public MemoryRetainer {
uint64_t flags_;
uint64_t thread_id_;
std::string thread_name_;
std::unordered_set<worker::Worker*> sub_worker_contexts_;
#if HAVE_INSPECTOR

View file

@ -390,6 +390,7 @@
V(table_string, "table") \
V(target_string, "target") \
V(thread_id_string, "threadId") \
V(thread_name_string, "threadName") \
V(ticketkeycallback_string, "onticketkeycallback") \
V(timeout_string, "timeout") \
V(time_to_first_byte_string, "timeToFirstByte") \

View file

@ -685,6 +685,16 @@ NODE_EXTERN Environment* CreateEnvironment(
ThreadId thread_id = {} /* allocates a thread id automatically */,
std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {});
NODE_EXTERN Environment* CreateEnvironment(
IsolateData* isolate_data,
v8::Local<v8::Context> context,
const std::vector<std::string>& args,
const std::vector<std::string>& exec_args,
EnvironmentFlags::Flags flags,
ThreadId thread_id,
std::unique_ptr<InspectorParentHandle> inspector_parent_handle,
std::string_view thread_name);
// Returns a handle that can be passed to `LoadEnvironment()`, making the
// child Environment accessible to the inspector as if it were a Node.js Worker.
// `child_thread_id` can be created using `AllocateEnvironmentThreadId()`

View file

@ -33,6 +33,7 @@ using v8::Local;
using v8::Locker;
using v8::Maybe;
using v8::Name;
using v8::NewStringType;
using v8::Null;
using v8::Number;
using v8::Object;
@ -89,6 +90,15 @@ Worker::Worker(Environment* env,
Number::New(env->isolate(), static_cast<double>(thread_id_.id)))
.Check();
object()
->Set(env->context(),
env->thread_name_string(),
String::NewFromUtf8(env->isolate(),
name_.data(),
NewStringType::kNormal,
name_.size())
.ToLocalChecked())
.Check();
// Without this check, to use the permission model with
// workers (--allow-worker) one would need to pass --allow-inspector as well
if (env->permission()->is_granted(
@ -365,7 +375,8 @@ void Worker::Run() {
std::move(exec_argv_),
static_cast<EnvironmentFlags::Flags>(environment_flags_),
thread_id_,
std::move(inspector_parent_handle_)));
std::move(inspector_parent_handle_),
name_));
if (is_stopped()) return;
CHECK_NOT_NULL(env_);
env_->set_env_vars(std::move(env_vars_));
@ -1239,6 +1250,16 @@ void CreateWorkerPerContextProperties(Local<Object> target,
Number::New(isolate, static_cast<double>(env->thread_id())))
.Check();
target
->Set(env->context(),
env->thread_name_string(),
String::NewFromUtf8(isolate,
env->thread_name().data(),
NewStringType::kNormal,
env->thread_name().size())
.ToLocalChecked())
.Check();
target
->Set(env->context(),
FIXED_ONE_BYTE_STRING(isolate, "isMainThread"),

View file

@ -0,0 +1,18 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const { Worker, threadName, workerData } = require('worker_threads');
const name = 'test-worker-thread-name';
if (workerData?.isWorker) {
assert.strictEqual(threadName, name);
process.exit(0);
} else {
const w = new Worker(__filename, { name, workerData: { isWorker: true } });
assert.strictEqual(w.threadName, name);
w.on('exit', common.mustCall(() => {
assert.strictEqual(w.threadName, null);
}));
}