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

Need to document how to clone clonable objects like Arc<> into a service_fn() in Hyper #2446

Closed
adamierymenko opened this issue Feb 26, 2021 · 1 comment · Fixed by #2539
Closed
Labels
A-docs Area: documentation.

Comments

@adamierymenko
Copy link

adamierymenko commented Feb 26, 2021

In the existing example code, the way to get your own clonable objects like Arc<> into a Hyper service is extremely non-obvious. It took me hours to figure it out. Sure more experience Rust users might find it easier, but it'd be helpful to newer Rust programmers to show and explain such a common thing. Also doesn't help that async is newer in Rust and documentation for how to do common things in async is still somewhat sparse.

Here's how I did it:

        let service = service.clone();
        let server = tokio::task::spawn(builder.serve(make_service_fn(move |_| {
            let service = service.clone();
            async move {
                Ok::<_, Infallible>(service_fn(move |req: Request<Body>| {
                    let service = service.clone();
                    async move {
                        web_handler(service, req).await
                    }
                }))
            }
        })).with_graceful_shutdown(async { let _ = shutdown_rx.await; }));

NOTE: service is something from my code, not the hyper "service."

The "service" is an Arc<> containing a Sync+Send object. If you do the obvious thing and use simple "async move" closures, you get some rather cryptic errors about inability to move blah blah blah. You instead have to give it conventional function closures that clone the object and then return an async closure with a copy per async closure.

This way clone() happens for each web request and you get the expected behavior of Arc<> in the context of asynchronous "pseudo-threads." (Async tasks are not threads but can be thought of as almost threads re: ownership and reference counting semantics.)

@davidpdrsn
Copy link
Member

I have been in the exact same situation several times and I agree the errors messages aren't great. I'll try and work on adding a better example to the server docs.

For your particular example I would probably write it like this:

let service = service.clone();

let hyper_service = service_fn(move |req: Request<Body>| web_handler(service.clone(), req));

let make_service = make_service_fn(move |_| {
    let hyper_service = hyper_service.clone();
    async move { Ok::<_, Infallible>(hyper_service.clone()) }
});

let server = builder.serve(make_service).with_graceful_shutdown(async {
    let _ = shutdown_rx.await;
});

let server_join_handle = tokio::task::spawn(server);

I haven't actually tested this but I believe it should compile. Its not a big improvement but might be slightly easier to read.

I'm also working on a fix for #2154 which will improve the ergonomics quite a bit.

davidpdrsn added a commit that referenced this issue May 6, 2021
It can sometimes be tricky to discover where to use `move` closures,
`async move {}`, and `.clone()` when creating a server. This adds a
slightly more bigger example that will hopefully help some.

Fixes #2446
@davidpdrsn davidpdrsn added the A-docs Area: documentation. label May 7, 2021
seanmonstar pushed a commit that referenced this issue May 11, 2021
It can sometimes be tricky to discover where to use `move` closures,
`async move {}`, and `.clone()` when creating a server. This adds a
slightly more bigger example that will hopefully help some.

Fixes #2446
BenxiangGe pushed a commit to BenxiangGe/hyper that referenced this issue Jul 26, 2021
It can sometimes be tricky to discover where to use `move` closures,
`async move {}`, and `.clone()` when creating a server. This adds a
slightly more bigger example that will hopefully help some.

Fixes hyperium#2446
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-docs Area: documentation.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants