| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
There was a problem hiding this comment.
I think this all looks fine.
Sorry, something went wrong.
Good point. I think I should.
Yes, I forgot about it.
I don't think so. The communication to accept new connections uses the same port which is already in place for communication with the parent thread. I just added a new message. |
Sorry, something went wrong.
|
@GeoffreyBooth Modifications done. |
Sorry, something went wrong.
There was a problem hiding this comment.
This drives workers further away from web workers and I'm not sure what it solves since:
I won't block but I'm not a fan of this API (because it seems inherently race conditiony)
Sorry, something went wrong.
There was a problem hiding this comment.
I think I see the direction and with the requirements of having an arbitrary thread start the unique HooksThread I don't see an alternative to this or something similar. Personally I still believe that restricting the usage of the customization hooks (like by having the main thread be the responsible thread for the configuration of the hooks for the whole process) would be a way that would allow easier, more predictable code.
Apart from that, I found just a few small things in first pass. I would check the code in more detail in the next days and give more feedback after a few tries with #53200 using this. I'm not sure it could cover all races like the one I try to talk about: #53200 (comment)
Sorry, something went wrong.
@benjamingr why? |
Sorry, something went wrong.
I can see it, but I think it's necessary to allow better intra-process communication.
They can, indirectly. We might need extended documentation for this, but the general idea is that workers sync up (and share their threadId via BroadcastChannel. When both workers are ready, one can start a connection to the other one.
Not really. It's really hard to properly propagate ports, especially if you think about several level of workers. With this architecture instead a worker on level 9 can advertise its threadId via BroadcastChannel and the interested parties will be able to directly connect without forwarding anything.
See my next comment. |
Sorry, something went wrong.
|
After @benjamingr and @dygabo commented I double checked and there was a possible race condition when a worker was blocked during a connect and a connection request arrived on itself. The connect with my last push becomes async, while the connection listener can now return a Promise. This solves the race condition. |
Sorry, something went wrong.
There was a problem hiding this comment.
I tend to agree with @benjamingr -- it's not ideal to introduce further differences to other thread implementations.
Nowadays if you, for instance, have a 10-level workers hierarchy and you want the level 2 to speak to a worker on level 9 you have to forward a port down 7 levels somehow.
Is this a common use case? I am genuinely curious because it reminds me of anti-patterns in traditional OOP design.
Sorry, something went wrong.
|
Thanks, the main race condition I noticed was addressed. Now I'm trying to come up with the use case. I need to know the threadId of the worker I'm connecting to - how do I get it? Can't whomever gave it to me give me a created MessagePort instead? Also:
This sounds incorrect? It should wait for a connection listener to exist so there isn't a race between the worker setting up a connection listener and the other thread calling worker.connect. As for the other issue (adding more APIs to worker). I would strongly prefer it if these were static methods (that would ideally also work or can be made to work with web workers). That would address our "standards like" thing (Worker) not deviating from the spec further while it still being possible to add the API. i.e. worker_threads.connect(worker, target, date) and worker_threads.setConnectionListener(worker, fn). This is what we've done in events (with EventTarget) for example and how we've extended standard APIs in the past. |
Sorry, something went wrong.
There was a problem hiding this comment.
I left a few comments and I think the API should be amended, I also didn't thoroughly review for race conditions.
I mostly agree with James that we should return synchronously and update the message port rather than return a promise if possible (rather than have 2 APIs).
That said, I understand the use case, the code seems reasonable (I haven't audited it beyond reading it, building it locally and playing a bit with it)- and this is a new experimental feature. There is plenty of time to discuss/amend it while it's being experimented with before being stable.
Sorry, something went wrong.
|
The notable-change PRs with changes that should be highlighted in changelogs. label has been added by @benjamingr. Please suggest a text for the release notes if you'd like to include a more detailed summary, then proceed to update the PR description with the text or a link to the notable change suggested text comment. Otherwise, the commit will be placed in the Other Notable Changes section. |
Sorry, something went wrong.
| const { port1, port2 } = new MessageChannel(); | ||
|
|
||
| // Make sure the event loop does not exist before this is completed | ||
| port1.ref(); |
There was a problem hiding this comment.
The ref() and unref() a few lines below are on a sync call path. Is it really needed?
And if it is, why is it not needed across the async await promise below?
Sorry, something went wrong.
|
|
||
| // Remove reference to the port used for inter-thread communication | ||
| { | ||
| Mutex::ScopedLock message_ports_lock(messagePortsMutex); |
There was a problem hiding this comment.
consider to move this scope before the Mutex::ScopedLock lock(mutex_); to avoid unneeded nesting of locks.
Sorry, something went wrong.
| // Remove reference to the port used for inter-thread communication | ||
| { | ||
| Mutex::ScopedLock message_ports_lock(messagePortsMutex); | ||
| message_ports.erase(thread_id_.id); |
There was a problem hiding this comment.
In case there are other cases to exit a worker (e.g. unhandled exception, kill from parent,...) such an erase needs to be also added in that places.
Sorry, something went wrong.
|
FWIW I'm not sure if these new APIs will allow to solve the problem of #53200. |
Sorry, something went wrong.
|
After a careful analysis, I came to a solution which is way simpler, it doesn't mess with C++ and it allows the same communication. See #53682. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
This PR adds two new API to worker_threads that allow for cross-thread communication via MessagePorts.
A thread can invoke worker.connect to start a new connection to another thread. This method is blocking. Upon success, the return value is a MessagePort which can be used to exchange messages.
The core idea is that a thread willing to accept connections from other thread uses worker.setConnectionsListener to install a callback that it is invoked with a thread id, a port and (optional) data each time another thread attempts a connection.
The listener can return true to accept the connection. Any other return value will result in the connection being refused.
By default, if a thread has no listener associated, the connection will be refused.
Notable Change Text
A new set of experimental APIs has been added to worker_threads: connect and setConnectionsListener. These APIs aim to simplify 1-1 inter-thread communication in Node.js
Every thread (including the main one) can start a connection to any another thread (including the main one) using the connect API and providing the target threadId.
If the connection is successful, the call will return a MessagePort that can be used for the communication.
A thread can opt-in to receive incoming connections by calling the setConnectionsListener API. The listener will be invoked for each connection attempt and must return true to accept the connection. A thread without a connection listener will refused any connection by default.