-
Notifications
You must be signed in to change notification settings - Fork 426
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
Add ?Send futures support in async-await branch #425
Comments
I don't think we'll be able to fit Supporting Your use case seems to be dealing with a synchronous database connection? Longer synchronous operations need to be delegated to a thread pool. Which is totally sensible for database queries if your DB api does not support async (yet). Below is a super simple (suboptimal) code snippet as an example for such a threadpool that I wipped up last week. #[derive(Clone)]
pub struct SyncThreadPool {
pool: Arc<Mutex<threadpool::ThreadPool>>,
}
impl SyncThreadPool {
pub fn new(threads: usize) -> Self {
let pool = threadpool::ThreadPool::new(threads);
Self {
pool: Arc::new(Mutex::new(pool)),
}
}
pub async fn execute<T, F>(&self, f: F) -> Result<T, failure::Error>
where
T: Send + 'static,
F: FnOnce() -> T + Send + 'static,
{
let (tx, rx) = futures::channel::oneshot::channel();
let wrapped = move || {
let output = f();
tx.send(output)
.map_err(|_| ())
.expect("Could not send completion message");
};
self.pool.lock().unwrap().execute(wrapped);
rx.await
.map_err(|_| failure::format_err!("Pool execution failed"))
}
} |
Nope, it's async, however is
Usual CRUD with database is quite a case. There is no need to share futures between threads. Each request does it job in its own thread quite OK as there is no CPU-bound tasks. As for me the best solution would be to have |
I agree, in theory. In practice I think it's impossible right now.
The problem is that traits are involved. The resolver methods on the I think this would theoretically be possible if each But this is currently impossible because a lifetime is involved, which would require higher kinded types/ATC support. I'll think about this more a bit (and would very much welcome a solution), but I'm pessimistic. (yes in theory we could have a feature that toggles on/off the sync + send bounds, but that would be really messy)
I thought that just applies to Are using actors together with
The benefit of async for juniper is allowing multiple DB/http/whatever requests to run concurrently. The only benefit would be allowing multiple requests to make progress on the same thread, but I don't think that makes sense any sense when sync network calls are in the mix. Everything would block/starve each other and your server would be very limited in throughput. You'd need multiple threads anyway. An alternative for your situation could be running a dedicated runtime for juniper and integrate with the actix runtime via channels. |
That's exactly the point.
There is no sync/blocking calls in our case.
We're using
Yup, that sounds like a good hack for an immediate solution. Thanks for pointing to it 🙏
Thank you for detailed explanation, pointing to the problem causes and paying so much attention to all this. In next few days I'll try to dig into code deeper and think about it from my side too. |
Ah I misunderstood the problem, yes of course it makes sense in this context. What I don't understand is why the Can you share a bit more of your code? The error message indicates that it is actually your resolver that relies on something that is |
Yes. Our DB interaction layer provides So, the overall flow for request is the following: If we have had |
I'm closing this for now. The problem is on my radar. Feel free to continue discussion in the main async issue ( #2 ). |
@nWacky good news, I think I might have found a way to do this reasonably well. |
This is still a big pain point in the current I'd like to elaborate on this, however don't really understand the right direction.
@theduke would you be so kind to share some thoughts about how this can be acomplished? @davidpdrsn @LegNeato do you have any ideas/thoughts about that? |
I haven't looked into this at all but I wonder if we can use something like https://rust-lang.github.io/async-book/07_workarounds/04_send_approximation.html |
Is your feature request related to a problem? Please describe.
Sometimes it's necessary to run not
Send
future in juniper handler (for example to get data from database). However, when trying to run such future I get the following error:Describe the solution you'd like
It would be nice to be able to use an option to use
!Send
futures in juniper, ideally with?Send
option on#[juniper::object]
macro (like in async_trait )I have tried removing Send bound from everywhere and it works fine, but then it's not possible to use futures from juniper as
Send
futures (for example, I cannot callreq.execute_async(schema, context).boxed().await
)I don't think that it would be possible to have such option on
#[juniper::object]
macro becauseSend
marker is defined in trait, not in it's implementantion.I think it could be done with a cargo.toml feature, but then it won't be possible to use both
Send
and!Send
futures in one projectDescribe alternatives you've considered
I have considered changing database connection function, but it decreases performance
The text was updated successfully, but these errors were encountered: