Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions doc/api/diagnostics_channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,17 @@ const channel = diagnostics_channel.channel('my-channel');
added:
- v18.7.0
- v16.17.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/65383
description: Returns a `Disposable` which removes the handler.
-->

* `name` {string|symbol} The channel name
* `onMessage` {Function} The handler to receive channel messages
* `message` {any} The message data
* `name` {string|symbol} The name of the channel
* Returns: {Disposable} A Disposable that removes the message handler.

Register a message handler to subscribe to this channel. This message handler
will be run synchronously whenever a message is published to the channel. Any
Expand All @@ -192,6 +197,32 @@ diagnostics_channel.subscribe('my-channel', (message, name) => {
});
```

The returned Disposable removes the message handler, which allows the
subscription to be scoped with the [`using`][] syntax. Disposing it more than
once has no further effect.

```mjs
import diagnostics_channel from 'node:diagnostics_channel';

{
using subscription = diagnostics_channel.subscribe('my-channel', (message, name) => {
// Received data
});
}
// The handler is removed on scope exit
```

```cjs
const diagnostics_channel = require('node:diagnostics_channel');

{
using subscription = diagnostics_channel.subscribe('my-channel', (message, name) => {
// Received data
});
}
// The handler is removed on scope exit
```

#### `diagnostics_channel.unsubscribe(name, onMessage)`

<!-- YAML
Expand Down Expand Up @@ -425,6 +456,9 @@ added:
- v15.1.0
- v14.17.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/65383
description: Returns a `Disposable` which removes the handler.
- version:
- v24.8.0
- v22.20.0
Expand All @@ -440,6 +474,7 @@ changes:
* `onMessage` {Function} The handler to receive channel messages
* `message` {any} The message data
* `name` {string|symbol} The name of the channel
* Returns: {Disposable} A Disposable that removes the message handler.

Register a message handler to subscribe to this channel. This message handler
will be run synchronously whenever a message is published to the channel. Any
Expand All @@ -465,6 +500,39 @@ channel.subscribe((message, name) => {
});
```

The returned Disposable removes the message handler, which allows the
subscription to be scoped with the [`using`][] syntax instead of pairing the
call with [`channel.unsubscribe(onMessage)`][]. Disposing it more than once has
no further effect.

```mjs
import diagnostics_channel from 'node:diagnostics_channel';

const channel = diagnostics_channel.channel('my-channel');

{
using subscription = channel.subscribe((message, name) => {
// Received data
});
console.log(channel.hasSubscribers); // true
}
console.log(channel.hasSubscribers); // false
```

```cjs
const diagnostics_channel = require('node:diagnostics_channel');

const channel = diagnostics_channel.channel('my-channel');

{
using subscription = channel.subscribe((message, name) => {
// Received data
});
console.log(channel.hasSubscribers); // true
}
console.log(channel.hasSubscribers); // false
```

#### `channel.unsubscribe(onMessage)`

<!-- YAML
Expand Down Expand Up @@ -770,6 +838,10 @@ dynamically.
added:
- v19.9.0
- v18.19.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/65383
description: Returns a `Disposable` which removes the handlers.
-->

* `subscribers` {Object} Set of [TracingChannel Channels][] subscribers
Expand All @@ -778,6 +850,8 @@ added:
* `asyncStart` {Function} The [`asyncStart` event][] subscriber
* `asyncEnd` {Function} The [`asyncEnd` event][] subscriber
* `error` {Function} The [`error` event][] subscriber
* Returns: {Disposable} A Disposable that removes every subscriber the call
registered.

Helper to subscribe a collection of functions to the corresponding channels.
This is the same as calling [`channel.subscribe(onMessage)`][] on each channel
Expand Down Expand Up @@ -831,6 +905,46 @@ channels.subscribe({
});
```

The returned Disposable removes every subscriber the call registered, which
allows the whole set to be scoped with the [`using`][] syntax. Disposing it more
than once has no further effect.

```mjs
import diagnostics_channel from 'node:diagnostics_channel';

const channels = diagnostics_channel.tracingChannel('my-channel');

{
using subscription = channels.subscribe({
start(message) {
// Handle start message
},
end(message) {
// Handle end message
},
});
}
// Both handlers are removed on scope exit
```

```cjs
const diagnostics_channel = require('node:diagnostics_channel');

const channels = diagnostics_channel.tracingChannel('my-channel');

{
using subscription = channels.subscribe({
start(message) {
// Handle start message
},
end(message) {
// Handle end message
},
});
}
// Both handlers are removed on scope exit
```

#### `tracingChannel.unsubscribe(subscribers)`

<!-- YAML
Expand Down Expand Up @@ -1208,11 +1322,17 @@ if (wc.hasSubscribers) {

<!-- YAML
added: v26.1.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/65383
description: Returns a `Disposable` which removes the handlers.
-->

* `handlers` {Object} Set of channel subscribers
* `start` {Function} The start event subscriber
* `end` {Function} The end event subscriber
* Returns: {Disposable} A Disposable that removes every subscriber the call
registered.

Subscribe to the bounded channel events. This is equivalent to calling
[`channel.subscribe(onMessage)`][] on each channel individually.
Expand Down Expand Up @@ -1247,6 +1367,46 @@ wc.subscribe({
});
```

The returned Disposable removes every subscriber the call registered, which
allows the whole set to be scoped with the [`using`][] syntax. Disposing it more
than once has no further effect.

```mjs
import { boundedChannel } from 'node:diagnostics_channel';

const wc = boundedChannel('my-operation');

{
using subscription = wc.subscribe({
start(message) {
// Handle start
},
end(message) {
// Handle end
},
});
}
// Both handlers are removed on scope exit
```

```cjs
const { boundedChannel } = require('node:diagnostics_channel');

const wc = boundedChannel('my-operation');

{
using subscription = wc.subscribe({
start(message) {
// Handle start
},
end(message) {
// Handle end
},
});
}
// Both handlers are removed on scope exit
```

#### `boundedChannel.unsubscribe(handlers)`

<!-- YAML
Expand Down Expand Up @@ -1986,6 +2146,7 @@ statement, since both are still in use while the event is being delivered; see
[`process.execve()`]: process.md#processexecvefile-args-env
[`start` event]: #startevent
[`statement.close()`]: sqlite.md#statementclose
[`using`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using
[`worker_threads.locks`]: worker_threads.md#worker_threadslocks
[context loss]: async_context.md#troubleshooting-context-loss
[thenable object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables
60 changes: 59 additions & 1 deletion lib/diagnostics_channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,27 @@ function maybeMarkInactive(channel) {
}
}

class ChannelSubscription {
#channel;
#subscription;

constructor(channel, subscription) {
this.#channel = channel;
this.#subscription = subscription;
}

[SymbolDispose]() {
const channel = this.#channel;
if (channel === undefined) return;

const subscription = this.#subscription;
this.#channel = undefined;
this.#subscription = undefined;

channel.unsubscribe(subscription);
}
}

class RunStoresScope {
#stack;

Expand Down Expand Up @@ -142,6 +163,7 @@ class ActiveChannel {
ArrayPrototypePush(this._subscribers, subscription);
channels.incRef(this.name);
if (this._index !== undefined) dc_binding.subscribers[this._index]++;
return new ChannelSubscription(this, subscription);
}

unsubscribe(subscription) {
Expand Down Expand Up @@ -230,7 +252,7 @@ class Channel {

subscribe(subscription) {
markActive(this);
this.subscribe(subscription);
return this.subscribe(subscription);
}

unsubscribe() {
Expand Down Expand Up @@ -324,6 +346,27 @@ function channelFromMap(nameOrChannels, name, className) {
nameOrChannels);
}

class HandlersSubscription {
#target;
#handlers;

constructor(target, handlers) {
this.#target = target;
this.#handlers = handlers;
}

[SymbolDispose]() {
const target = this.#target;
if (target === undefined) return;

const handlers = this.#handlers;
this.#target = undefined;
this.#handlers = undefined;

target.unsubscribe(handlers);
}
}

class BoundedChannelScope {
#context;
#end;
Expand Down Expand Up @@ -380,6 +423,12 @@ class BoundedChannel {

this[name]?.subscribe(handlers[name]);
}

return new HandlersSubscription(this, {
__proto__: null,
start: handlers.start,
end: handlers.end,
});
}

unsubscribe(handlers) {
Expand Down Expand Up @@ -486,6 +535,15 @@ class TracingChannel {
if (handlers.error) {
this.error.subscribe(handlers.error);
}

return new HandlersSubscription(this, {
__proto__: null,
start: handlers.start,
end: handlers.end,
asyncStart: handlers.asyncStart,
asyncEnd: handlers.asyncEnd,
error: handlers.error,
});
}

unsubscribe(handlers) {
Expand Down
Loading
Loading