-
Notifications
You must be signed in to change notification settings - Fork 147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Worker v2 #200
Worker v2 #200
Conversation
It would be nice if you could also add tests for worker implementation. Assuming that's possible, of course. |
It's actually relatively cumbersome to compile workers at the moment. However, the next version of trunk has introduced worker support which we may have a better chance after the release of the next version of Trunk. |
Can this be completed now that trunk supports workers? |
FYI: I had a problem moving to v2, because the resource path was missing this prefix: |
I think this has been fixed in 64a08e0 as it now uses the URL of current page as base. If it does not work, could you provide the URL of the page and the path of the worker that is passed to .spawn()? |
5a0bd6 looks incredible, thank you! |
yup, this works, checked in a-b-street/osm2lanes@f1eff7d Now I need to figure out how to integrate rkyv as an alternative encoding to bincode (bincode doesn't play nice with serde's flatten) |
ah, I spoke too soon. This still depends on serde. Maybe there is another serde-compatible binary coding crate that doesn't have the same problems. |
You should be able to use |
Thanks @futursolo, I got this working end to end now here: a-b-street/osm2lanes#214 I will keep this updated with your changes. |
# Conflicts: # crates/worker/src/worker/private.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this PR and all the amazing work that you've done. Sorry it look me a little while to get to this.
Since this is a complete rewrite, I think we should have a migration guide (not exactly sure where it would go). What do you think? I think a page on the website or a markdown file in this directory would do the job.
crates/worker/src/codec.rs
Outdated
|
||
/// Default message encoding with [bincode]. | ||
#[derive(Debug)] | ||
pub struct Bincode {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub struct Bincode {} | |
pub struct Bincode; |
They have different semantics. The current implementation can't be created like:
let c = Bincode; // incorrect
let c = Bincode {}; // correct
I think it's better to remove the { }
. Adding fields will be a breaking change regardless.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You will never need to instantiate the Bincode struct.
It is supposed to be used with Worker::spawner().encoding::<Bincode>().spawn()
.
But I have removed it anyways.
crates/worker/src/codec.rs
Outdated
/// Default message encoding with [bincode]. | ||
#[derive(Debug)] | ||
pub struct Bincode {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should bincode be the default, with no way to opt out? Postcard recently hit 1.0, which is no_std so it should have a smaller footprint in the binary. I think we should allow users to customize it. A simple feature flag (enabled by default) will be enough here. Those who want to customize can implement Codec
manually
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should bincode be the default, with no way to opt out?
If we do not provide a default encoding, it means that users will have to specify Codec
for every agent.
I don't think this would be a feature that most users would want to use. Assuming a default encoding would result in a simplified encoding.
Dead code elimination is effective in removing Bincode when it is not selected.
Those who want to customize can implement Codec manually
This is already possible by specifying a Codec
other than Bincode
. Any type that implements Codec
can be passed to encoding()
method of Spawner and Registrar.
crates/worker/src/native_worker.rs
Outdated
}; | ||
let closure = Closure::wrap(Box::new(handler) as Box<dyn Fn(MessageEvent)>); | ||
self.set_onmessage(Some(closure.as_ref().unchecked_ref())); | ||
// Memory leak? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. This is a memory leak, the closure is never freed.
Is it possible to store the closure somewhere? If this is a hot path, the memory leak(s) can add up. How many times will this be called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have converted it to use into_js_value()
.
If the bundle is built with weak reference support, it will be tracked by the browser's GC and will be destroyed after it's not used.
// We need to hold the bridge until the worker resolves. | ||
let promise = Promise::new(&mut |_, _| {}); | ||
let _ = JsFuture::from(promise).await; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really understand this part. Shouldn't it be instant? Or do we need the tick from the micro task queue, after the promise is resolved?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The application is getting data from a "thread".
The main thread will not be able to see the message until it is notified by a thread synchronisation mechanism(MessageChannel
in this case). It will not be notified until control is handed back to the event loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know where the migration guide should reside in either.
But as it is completely rewritten, it might be better to simply advise users to re-implement their agent like what's advised in the yew-router
0.16 migration guide.
crates/worker/src/codec.rs
Outdated
|
||
/// Default message encoding with [bincode]. | ||
#[derive(Debug)] | ||
pub struct Bincode {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You will never need to instantiate the Bincode struct.
It is supposed to be used with Worker::spawner().encoding::<Bincode>().spawn()
.
But I have removed it anyways.
crates/worker/src/codec.rs
Outdated
/// Default message encoding with [bincode]. | ||
#[derive(Debug)] | ||
pub struct Bincode {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should bincode be the default, with no way to opt out?
If we do not provide a default encoding, it means that users will have to specify Codec
for every agent.
I don't think this would be a feature that most users would want to use. Assuming a default encoding would result in a simplified encoding.
Dead code elimination is effective in removing Bincode when it is not selected.
Those who want to customize can implement Codec manually
This is already possible by specifying a Codec
other than Bincode
. Any type that implements Codec
can be passed to encoding()
method of Spawner and Registrar.
crates/worker/src/native_worker.rs
Outdated
}; | ||
let closure = Closure::wrap(Box::new(handler) as Box<dyn Fn(MessageEvent)>); | ||
self.set_onmessage(Some(closure.as_ref().unchecked_ref())); | ||
// Memory leak? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have converted it to use into_js_value()
.
If the bundle is built with weak reference support, it will be tracked by the browser's GC and will be destroyed after it's not used.
// We need to hold the bridge until the worker resolves. | ||
let promise = Promise::new(&mut |_, _| {}); | ||
let _ = JsFuture::from(promise).await; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The application is getting data from a "thread".
The main thread will not be able to see the message until it is notified by a thread synchronisation mechanism(MessageChannel
in this case). It will not be notified until control is handed back to the event loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again for the PR!
Thanks also from me! I think this is a great improvement. |
This pull request simplifies Workers to have 1 single type.
This consists of the following changes:
PublicWorker
andPrivateWorker
WorkerSpawner
to supersedeWorker::bridge()
with a builder pattern to spawn workers. WorkerSpawner always spawn a new worker.WorkerLink
and opted forWorkerScope
directly.WorkerBirdge::fork()
which supports the former PublicWorker usage. It can "fork" the bridge with a different callback and HandlerId.This pull request is feature complete.
However, I have modified some associated types on messages which could cause the main implementation of Worker to not be able to be tree shaked automatically. I will test this as I update the yew-agent crate and turn this into a pull request once I have the new agent implementation ready.