Skip to content

BroadcastChannel doesn't fill in useful MessageEvent fields like source, or ports #59053

Open

Description

@jdmarshall

Please populate the Worker value in BroadcastChannel MessageEvents 'source' field the same way it is in WebWorkers.

There is currently no mechanism to compose Workers in the NodeJS APIs and this change would provide a mechanism to
solve that problem, if not for the general case, at least with only a small amount of additional bookkeeping on the part of
application developers.

Without a composition mechanism, it is extremely difficult to implement cross-cutting concerns between workers, and between workers and large subsystems in the main application. Which is problematic for many areas of production code including caching, telemetry, reloadable configuration, and security.

Fundamentally, there is no mechanism to tell if a Worker has terminated. And since Workers tend to be used for tasks with high utilization of the event toop, even sending a message to ask if anyone is still listening to the BroadcastChannel is not guaranteed to work on any reasonable time frame, and in particular for cross-cutting concerns who can't know what, for instance, the cutoff time is for image processing in the Image Worker, and that the Cache Worker has a cutoff of 1/100th of that time. Which then leads to a scenario where you've decided a Worker is dead and then the same worker pops back up 10 seconds later. What you need is worker.on('exit') which is unambiguous.

Version

All versions

Platform

All Platforms

Subsystem

node:worker_threads

What steps will reproduce the bug?

        const util = require('util');
	const channel = new BroadcastChannel('example');

	if (isMainThread) {
		channel.addEventListener('message', evt => {
			console.log(util.inspect(evt)); // breakpoint here
		});
	} else {
		channel.postMessage('hello');
        }

The Message Event recieved looks like


MessageEvent {
  type: 'message',
  defaultPrevented: false,
  cancelable: false,
  timeStamp: 444.018666
}

How often does it reproduce? Is there a required condition?

Always. Seems to be by design, and the design may have drifted from the current web standards over time.

What is the expected behavior? Why is that the expected behavior?

That I get a Worker object to facilitate lifecycle management and IPC coordination.

What do you see instead?

empty string, empty array. And no other mechanism in the Node API to interrogate the running isolates to find this information.

Additional information

No response

Activity

  1. SudhansuBandha commented on Jul 7, 2026

    @SudhansuBandha
    Contributor

    @jdmarshall Please have a look at the proposed changes in this PR. I have updated the source field of Broadcast Channel events to reflect worker thread ids

  2. jdmarshall commented on Jul 7, 2026

    @jdmarshall
    Author

    But the spec has a Worker object in the source field, not the threadId.

  3. jdmarshall commented on Aug 11, 2026

    @jdmarshall
    Author

    @SudhansuBandha my project is concerned about the potential to not detect worker termination without having access to the worker object expected in the MessageEvent. ThreadId isn't going to support the full lifecycle needed for robust use of this communication channel.

  4. SudhansuBandha commented on Aug 12, 2026

    @SudhansuBandha
    Contributor

    Will it be feasible for Broadcast Channel to share sender's worker object to acess full lifecycle of worker considering that workers run on different isolates? Maybe creating an extension in Broadcast Channel address this since event.source is null.
    @jasnell would love to have your feeback on this before making any changes.

  5. jdmarshall commented on Aug 12, 2026

    @jdmarshall
    Author

    I suppose that's a question of how much of the logic for WebWorkers is within V8 and how much of it is tacked on by chrome.

  6. jdmarshall commented on Aug 12, 2026

    @jdmarshall
    Author

    I'm going to change the summary for this story a bit because the ask I'm making has much bigger implications than I think I have communicated. There's a giant hole in the middle of the Worker API specification and I believe this change fills in most of that hole, while lesser solutions do essentially nothing to fill it in. Which is why I'm being particular about how I'd like it to be fixed.

  7. SudhansuBandha commented on Aug 20, 2026

    @SudhansuBandha
    Contributor

    MessageEvent.source should remain unchanged, since for BroadcastChannel it is expected to be null under the web platform semantics.

    Exposing the actual Worker object through source could also unintentionally expose APIs such as terminate(), ref(), and unref(), which should not necessarily be available to another Worker.

    For Worker-to-Worker communication, postMessageToThread() already provides communication between threads based on the existing MessagePort infrastructure that can be used for direct inter-worker communication.

    I think creating an extension for events of BroadcastChannel originating Worker to providing reliable lifecycle information might be helpful to address this issue

  8. SudhansuBandha commented on Aug 27, 2026

    @SudhansuBandha
    Contributor

    @jdmarshall PTAL at this PR. I have created this setup to emit events which get triggered when worker exits in a Broadcast Channel. I know this might not solve all the lifecycle events tracking but hopefully this can be a good start based on which we can make further progress.

  9. jdmarshall commented on Aug 27, 2026

    @jdmarshall
    Author

    That would help but I’m still curious why it’s difficult to emulate the browser API? Node isnt doing what Chrome already has.

  10. SudhansuBandha commented on Aug 27, 2026

    @SudhansuBandha
    Contributor

    One problem with populating source is that it exposes native worker apis like terminate(), ref(), and unref() to other threads which can lead to termination of source worker by another worker. That is something which should not be allowed.

  11. jdmarshall commented on Aug 27, 2026

    @jdmarshall
    Author

    I don't know if I agree with that. We are all running in the same sandbox, employed by the same bosses. The security guarantee is if you do something egregious you lose your job, not a VM enforcing security constraints.

    I can always just call process.exit(0) in main and kill the entire VM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    workerIssues and PRs related to the worker_threads module and Worker API.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions