-
-
Notifications
You must be signed in to change notification settings - Fork 86
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
Document cancel safety #104
Comments
Notes toward documentation on this topic: Send
Currently, upon Drop, the Receive
As a general design principle, we decided not to worry about users who leak or I do not quite understand the cancellation safety doc in tokio, to be perfectly honest. It is worded as very specific to |
Bit confused about this. Does this mean that if
That sounds valid and reasonable to me.
I'm not a tokio dev, but my understanding is that they just use |
Yes, indeed. The item is sent into a queue of waiters. This is an optimisation for latency - the receiver doesn't need to wake the sender and then wait for the sender to wake, get polled, send the item, and then wake the receiver again. The receiver can just take the item and wake the sender. But, in some cases the sender could be dropped after item taken but before it is woken. |
By the way, could you elaborate on the usecase mentioned for cancellation safety in launchbadge/sqlx#2054 |
I see. So that means
Sure. For the mentioned fix to work, I need to make sure that |
Could the RAII guard be created before the send occurs? The worker thread would need to deal with the potential for spurious messages, however. This is similar to how you usually create a guard which notifies if something happens before checking if it has actually happened, or you check twice - once before creation and once after. This is in case the notification fires after checking and before creating the listener, as then the listening guard may never be woken. I'm not sure if this makes sense, but here is an example of this pattern. This may solve this particular issue (or maybe not!) but maybe looking at a cancellation-safe design would be good regardless, or for other use cases. |
Yes exactly. That could create the opposite problem - we could end up executing But there are other ways to solve this problem. I'm already pondering some ideas. Thanks for the input anyway! |
In theory, maybe the worker can keep track of whether the corresponding BEGIN has been executed and ignore it if so, but this is getting a bit off topic now :) Good luck! |
How does this work with bounded channels? This sounds like the sender isn't woken until the item is received, but no one expects a channel to behave like that with nonzero capacity. |
Just to clarify, if the channel has capacity, send async will return in one poll. So, this behavior of waiting only applies to when there is no capacity in the channel. When capacity is full, the sender goes into a queue of waiting senders, which stores its waker and the item. Then, when a receiver receives an item, there is now space in the channel, so the waiting sender is woken and the receiver puts that item on the channel. I think this was unclear in my original message, as I said "it may be received by a receiver at any point". This is better stated as it is pulled by a receiver from the pending queue into the channel's queue (an operation called By the way, please correct me if the code does not actually do this, but I think I'm reading it right here 🙂
It may seem slightly surprising at first, but I do not believe that this actually breaks any assumptions about bounded channels. The end result that the send will wait for capacity is the same. |
Oops sorry, that was an accidental close 😅 |
This is an interesting discussion and not something that has previous had much thought put into it. Given that we've pretty much "solved" (in the most primitive sense of the word) this issue on the receiving end for receiver slots, it might be viable to do something similar on the sending end, although I've not thought too much about that. If anybody is interested in looking into this further, I'd be happy to review code / give advice, but I'm not sure I've got enough free time to work on it myself, at least for the next few months. |
I think it's highly surprising that a It also weakens the guarantees of having a bounded channel as, if I understand correctly, you could essentially do |
This is not the case. When the future is dropped after now or never returns None, the waiter will be removed and the send will be canceled. |
I agree. It's something that should be documented or otherwise changed. As far as changing it goes, I may look into it in a successor to #84 |
From my understanding |
It's unclear whether
Sender::send_async
is cancel-safe. That is, does it guarantee that if the future returned from it is cancelled, the message is not sent? It would be great to document it. For inspiration, see tokio's docs: https://docs.rs/tokio/latest/tokio/sync/mpsc/struct.Sender.html#cancel-safetyThe text was updated successfully, but these errors were encountered: