-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Remove Sync
requirement for Streaming
#117
Comments
So I'm not sure if this is a bug because technically it was intentional but I'm not sure how to get both working. Thanks for opening this. |
I have a similar case, I am using hyper client in a response stream, I get: the trait it works with 0.1.0-alpha.4 as mentioned in OP, and fails in 0.1.0-alpha.6. I am not sure how to work around that problem. |
So I believe using a channel should work as a temporary solution. @abdul-rehman0 would you be able to use a channel and a spawned task instead? |
@LucioFranco using a channel and spawn works for me, Thanks. Changed the following code: let client = Client::new(URL);
let response: PreferencesResponse = client.get(&[("to", "to")]).await.unwrap(); To: let (response_sender, response_receiver) = oneshot::channel::<PreferencesResponse>();
tokio::spawn(async move {
let client = Client::new(URL);
let response: PreferencesResponse = client.get(&[("to", "to")]).await.unwrap();
response_sender.send(response);
});
let response = response_receiver.await.unwrap(); |
Cool, I think this is probably the correct solution for now. I think it makes sense to cover both send and sync for now in the trait object since users can just use a channel. |
I think the above solution works well for this, so I will close this issue, feel free to reopen if you have any more questions. |
I do understand the workaround with channels, but I can't get my head around why the response stream needs to be @LucioFranco you say the change to Thanks for your help! These explanations will really help me in my (long) journey to enlightenment about rust async 😄 |
IIUC another way to fix is pub struct AlwaysSync<T>(T);
// SAFETY: This is essentially mutex, but without `lock()`.
// alternative justification: &AlwaysSync can't be upgrared to &T.
unsafe impl<T: Send> Sync for AlwaysSync<T> {}
impl AlwaysSync {
fn get_mut(&mut self) -> &mut T {
&mut self.0
}
fn get_mut_pinned(self: Pin<&mut Self>) -> Pin<&mut T> {
// SAFETY: just a pin projection
unsafe {Pin::map_unchecked_map(self, |s| &mut s.0)}
}
}
impl<T: Stream> Stream for AlwaysSync<T> {
type Item = T::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.get_mut_pinned().poll_next(cx)
}
} |
Internally, we |
I believe there is no need to require If I have enough time, I'll try to make a PR relaxing Sync bounds. |
@MikailBag Yeah, I am not sure how that adds up fully with regards to rust's safety rules, but personally I don't think its worth it. A channel works well. |
Thanks for taking the time to answer. Not sure I understand how it all fits together, but I guess I won't without looking at the code in more details. 😃 |
So after some considerations, I now think that this pattern/problem is pretty popular. I published a tiny crate: https://github.com/MikailBag/weird-mutex (will publish to crates-io if someone asks for that) that allows one to avoid Sync bounds without writing unsafe code. For example, see [https://github.com/hyperium/tonic/compare/master...MikailBag:unsync] for patch deleting Without patching Tonic code, one can wrap their streams in WeirdMutex and these streams will become Sync. |
@MikailBag There is already something like it: https://github.com/Actyx/sync_wrapper and I've send a PR: Actyx/sync_wrapper#1 |
I understand there's kind of a workaround now, but given that |
Also, did we ever get an answer for why a |
The original motivation for making @LucioFranco I think this trait bound can be removed on Tonic now. |
Yay! Can we reopen this issue and get rid of the trait bound? |
Sync
requirement for Streaming
Okay, I've reopened this, I will revisit this in the next release of tonic. |
Hm I'm not sure this is possible since hyper's Tonic uses tonic/tonic/src/transport/server/mod.rs Line 400 in 31936e0
|
One can always "upgrade" |
The |
Relevant commit in hyper hyperium/hyper@1d553e5 |
As we learned [in Tonic] bodies don't need to be `Sync` because they can only be polled from one thread at a time. This changes axum's bodies to no longer require `Sync` and makes `BoxBody` an alias for `UnsyncBoxBody<Bytes, axum::Error>`. [in Tonic]: hyperium/tonic#117
As we learned [in Tonic] bodies don't need to be `Sync` because they can only be polled from one thread at a time. This changes axum's bodies to no longer require `Sync` and makes `BoxBody` an alias for `UnsyncBoxBody<Bytes, axum::Error>`. [in Tonic]: hyperium/tonic#117
As we learned [in Tonic] bodies don't need to be `Sync` because they can only be polled from one thread at a time. This changes axum's bodies to no longer require `Sync` and makes `BoxBody` an alias for `UnsyncBoxBody<Bytes, axum::Error>`. [in Tonic]: hyperium/tonic#117
This is a followup to the conversation in #81 (comment) - I decided to create a new ticket to raise awareness.
Bug Report
Version
tonic = "0.1.0-alpha.5"
Platform
Darwin JayMBP-2.local 18.7.0 Darwin Kernel Version 18.7.0: Sat Oct 12 00:02:19 PDT 2019; root:xnu-4903.278.12~1/RELEASE_X86_64 x86_64
Description
In older releases, we're able to use non-Sync futures, like
hyper::client::ResponseFuture
to yield items in a streaming response. #84 added a Sync trait bound to the pinnedStream
trait object returned by the service impl. The following code works with the previous version of tonic:Works with 0.1.0-alpha.4
And the updated code now fails:
Fails with 0.1.0-alpha.5
Compile error
The text was updated successfully, but these errors were encountered: