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

!Send handlers #362

Closed
jkelleyrtp opened this issue Oct 3, 2021 · 2 comments
Closed

!Send handlers #362

jkelleyrtp opened this issue Oct 3, 2021 · 2 comments

Comments

@jkelleyrtp
Copy link

jkelleyrtp commented Oct 3, 2021

Some datastructures are inherently non Send. It would be great if Axum could take advantage of Tokio's ability to run only thread-local tasks and only have Thread-local handlers.

Right now, handlers may be !Sync, but they must be Send. It would be great if handlers could be !Send and !Sync within their handling code - the creation of the task could be Send.

For reference, actix manually spins up an executor for each thread in a thread pool, then runs server futures on a LocalSet.

rust-lang/wg-async#87 (comment)

This means it's possible to support !Send handlers while also using the native runtime.

@davidpdrsn
Copy link
Member

davidpdrsn commented Oct 3, 2021

One cannot use !Send futures with hyper at least not the with the default tokio executor:

let svc = tower::service_fn(|_: Request<Body>| async {
    let rc = std::rc::Rc::new(());
    std::future::ready(()).await;
    rc.clone();
    Ok::<_, hyper::Error>(http::Response::new(Body::empty()))
});

hyper::Server::bind(&"".parse().unwrap())
    .serve(tower::make::Shared::new(svc))
    .await
    .unwrap();

This doesn't compile

error: future cannot be sent between threads safely
  --> src/tests/helpers.rs:45:10
   |
45 |         .serve(tower::make::Shared::new(svc))
   |          ^^^^^ future created by async block is not `Send`
   |
   = help: within `hyper::proto::h2::server::H2Stream<impl futures_util::Future, hyper::Body>`, the trait `std::marker::Send` is not implemented f
or `Rc<()>`
note: future is not `Send` as this value is used across an await
  --> src/tests/helpers.rs:39:9
   |
38 |         let rc = std::rc::Rc::new(());
   |             -- has type `Rc<()>` which is not `Send`
39 |         std::future::ready(()).await;
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later
...
42 |     });
   |     - `rc` is later dropped here

So not sure there is much we can do in axum.

Personally I think spawning a task and communicating via channels to be fine for working with !Send types.

Creating a runtime for each thread doesn't seem like its worth it. I don't know what the memory and performance implications are but to me it feels like the right approach to stick with tokio's multithreaded runtime.

@davidpdrsn
Copy link
Member

Think I'll close this for now as this isn't something we plan on adding support for. I think it would require changes that would hurt users who don't need !Send futures. If someone knows of a way to support both i would be interested to hear it.

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

No branches or pull requests

2 participants