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

Fixed an issue where the package loader was blocking the tokio runtime #4335

Merged
merged 4 commits into from
Mar 12, 2024

Conversation

john-sharratt
Copy link
Contributor

No description provided.

Copy link
Contributor

@Michael-F-Bryan Michael-F-Bryan left a comment

Choose a reason for hiding this comment

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

One thing we'll need to be careful of is to only ever use the BuiltinPackageLoader within a tokio context, otherwise we'll have "tried to use tokio outside of a runtime context" panics.

That was already a problem as of 7885976 (from #4204) when we originally introduced the tokio::task::block_in_place() calls though and we haven't seen panics in the last couple months, so maybe it'll be fine.

<rant>

The PR as it currently stands is fine and should mitigate some of the stability issues we were seeing on Edge, however it reiterates some concerns I have about the the way our wasmer_wasix::Runtime is structured and how we have dependencies between components.

As an example, the BuiltinPackageLoader requires access to a VirtualTaskManager because it needs to run blocking code. We are currently using tokio::task::spawn_blocking() which implicitly assumes the BuiltinPackageLoader will be used inside a tokio context.

A "cleaner" approach would be to either refactor BuiltinPackageLoader to accept an Arc<dyn VirtualTaskManager> in its constructor, but then it gets harder to create and a given BuiltinPackageLoader instance will always be coupled to that VirtualTaskManager instance.

We have similar coupling in other places which require things like a HTTP client. The BuiltinPackageLoader already depends on a HTTP client, but it's also used for things like the dependency resolver.

If we have have cross-component coupling like this anyway, we may as well make it explicit by passing the dependency in when they are used. For example:

#[async_trait::async_trait]
pub trait PackageLoader: Send + Sync + Debug {
    async fn load(&self, summary: &PackageSummary, http_client: &Arc<dyn HttpClient>) -> Result<Container, Error>;
}

(or instead of passing the HTTP client directly, we could pass in a &dyn Runtime or some &dyn PackageLoaderContext helper trait or whatever)

Hiding these cross-component dependencies like we have been so far doesn't make things cleaner. It actually makes the code harder to use because you need to instantiate components in a specific order and if you want to change one component out you need to recreate any components that depends on it. That's had a tangible effect on the WasmerJS public API because it means people can't do "obvious" things like updating the HTTP client after the runtime has already been instantiated (e.g. to add auth when using private packages).

</rant>

@syrusakbary
Copy link
Member

We probably want to pass a tokio handle to prevent cases where we call this without tokio running under the hood

@theduke theduke enabled auto-merge March 12, 2024 19:33
@theduke theduke merged commit 04ad072 into master Mar 12, 2024
59 checks passed
@theduke theduke deleted the fix-for-blocking-runtime branch March 12, 2024 20:16
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