-
-
Notifications
You must be signed in to change notification settings - Fork 91
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
refactor: do not cancel the task returned from async_imap Handle.wait_with_timeout
#6526
Conversation
d569d6e
to
a7b69cd
Compare
This fixes some code that did not look right: #6477 (comment) It should not result into infinite loop in any case, however. |
a7b69cd
to
605525f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From reading the source, wait_with_timeout()
does pretty much look cancellation-safe to me. The returned future only uses await
in two places:
let Ok(res) = timeout(dur, interruptible_stream.next()).await else {
this is using timeout()
itself, so it's obviously cancellation-safe.
handle_unilateral(resp, sender.clone()).await;
handle_unilateral()
is async
in order to send()
unsolicited responses into the channel. Not sure if that means that cancelling can cause unsolicited responses to get lost, but since we only use unsolicited responses to figure out whether we should fetch again, and we always fetch again after idle, this should be fine for us.
So, I'm like +/-0 on this PR since on the one hand it makes us use the API in a more "correct" way, OTOH it changes things without any pressing reason, which can always make things worse. I'll approve it anyway so that you can decide to merge it.
let context = context.clone(); | ||
let folder = folder.to_string(); | ||
|
||
tokio::spawn(async move { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a note that we wouldn't need tokio::spawn()
here, tokio::join!()
ing the two futures would suffice. But the current code has the advantage that it's only using simple concepts, whereas tokio::join!()
is somewhat of a harder to grasp concept, so, I'm not actually proposing to change anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how I can cancel the second "relay" future once I have put it into join
already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something with join set is probably possible, but the task is good enough.
I am not so sure everything async-imap does internally is correct as well, it needs review too. Wrapping reading of IMAP connection into A safer way to terminate IDLE would be to send |
605525f
to
fb9a9ae
Compare
I am pretty sure that this does not fix any bug, but I want to get rid of all future cancellations on code paths that keep Session (or better all code paths) because reasoning about future cancellations is very difficult and we have the bug with something going into infinite loop around this area. |
Handle.wait_with_timeout
Handle.wait_with_timeout
fb9a9ae
to
5e22af2
Compare
…t_with_timeout` This task is not guaranteed to be cancellation-safe and provides a stop token for safe cancellation instead. We should always cancel the task properly and not by racing against another future. Otherwise following call to Handle.done() may work on IMAP session that is in the middle of response, for example.
5e22af2
to
81e9628
Compare
This task is not guaranteed to be cancellation-safe and provides a stop token for safe cancellation instead. We should always cancel the task properly
and not by racing against another future.
Otherwise following call to Handle.done()
may work on IMAP session that is in the middle
of response, for example.