Skip to content
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

Merged
merged 34 commits into from
Jun 23, 2022
Merged

Worker v2 #200

merged 34 commits into from
Jun 23, 2022

Conversation

futursolo
Copy link
Collaborator

This pull request simplifies Workers to have 1 single type.

This consists of the following changes:

  1. Unifies PublicWorker and PrivateWorker
  2. Added a WorkerSpawner to supersede Worker::bridge() with a builder pattern to spawn workers. WorkerSpawner always spawn a new worker.
  3. Removed WorkerLink and opted for WorkerScope directly.
  4. 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.

@ranile
Copy link
Collaborator

ranile commented Mar 18, 2022

It would be nice if you could also add tests for worker implementation. Assuming that's possible, of course.

@futursolo
Copy link
Collaborator Author

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.

@droogmic
Copy link

Can this be completed now that trunk supports workers?

@droogmic
Copy link

FYI: I had a problem moving to v2, because the resource path was missing this prefix:
https://github.com/droogmic/gloo/blob/master/crates/worker/src/worker/mod.rs#L85-L89

@futursolo
Copy link
Collaborator Author

FYI: I had a problem moving to v2, because the resource path was missing this prefix:
https://github.com/droogmic/gloo/blob/master/crates/worker/src/worker/mod.rs#L85-L89

I think this has been fixed in 64a08e0 as it now uses the URL of current page as base.
Could you please try again?

If it does not work, could you provide the URL of the page and the path of the worker that is passed to .spawn()?

@futursolo futursolo marked this pull request as ready for review June 13, 2022 12:42
@droogmic
Copy link

5a0bd6 looks incredible, thank you!

@droogmic
Copy link

FYI: I had a problem moving to v2, because the resource path was missing this prefix:
https://github.com/droogmic/gloo/blob/master/crates/worker/src/worker/mod.rs#L85-L89

I think this has been fixed in 64a08e0 as it now uses the URL of current page as base. Could you please try again?

If it does not work, could you provide the URL of the page and the path of the worker that is passed to .spawn()?

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)

@droogmic
Copy link

5a0bd6 looks incredible, thank you!

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.

@futursolo
Copy link
Collaborator Author

serde-compatible binary coding

You should be able to use serde_json or serde-wasm-bindgen.
The message format accepts any type that supports structured clone.

@droogmic
Copy link

Thanks @futursolo, I got this working end to end now here: a-b-street/osm2lanes#214

I will keep this updated with your changes.

Copy link
Collaborator

@ranile ranile left a 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.


/// Default message encoding with [bincode].
#[derive(Debug)]
pub struct Bincode {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Copy link
Collaborator Author

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.

Comment on lines 18 to 20
/// Default message encoding with [bincode].
#[derive(Debug)]
pub struct Bincode {}
Copy link
Collaborator

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?

Copy link
Collaborator Author

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.

};
let closure = Closure::wrap(Box::new(handler) as Box<dyn Fn(MessageEvent)>);
self.set_onmessage(Some(closure.as_ref().unchecked_ref()));
// Memory leak?
Copy link
Collaborator

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?

Copy link
Collaborator Author

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.

crates/worker/src/registrar.rs Outdated Show resolved Hide resolved
Comment on lines +37 to +39
// We need to hold the bridge until the worker resolves.
let promise = Promise::new(&mut |_, _| {});
let _ = JsFuture::from(promise).await;
Copy link
Collaborator

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?

Copy link
Collaborator Author

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.

Copy link
Collaborator Author

@futursolo futursolo left a 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.


/// Default message encoding with [bincode].
#[derive(Debug)]
pub struct Bincode {}
Copy link
Collaborator Author

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.

Comment on lines 18 to 20
/// Default message encoding with [bincode].
#[derive(Debug)]
pub struct Bincode {}
Copy link
Collaborator Author

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.

};
let closure = Closure::wrap(Box::new(handler) as Box<dyn Fn(MessageEvent)>);
self.set_onmessage(Some(closure.as_ref().unchecked_ref()));
// Memory leak?
Copy link
Collaborator Author

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.

Comment on lines +37 to +39
// We need to hold the bridge until the worker resolves.
let promise = Promise::new(&mut |_, _| {});
let _ = JsFuture::from(promise).await;
Copy link
Collaborator Author

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.

Copy link
Collaborator

@ranile ranile left a 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!

@ranile ranile merged commit 52572bd into rustwasm:master Jun 23, 2022
@huntc
Copy link
Contributor

huntc commented Jun 23, 2022

Thanks also from me! I think this is a great improvement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants