-
Notifications
You must be signed in to change notification settings - Fork 514
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
Update NSUrlSessionHandler to cancel request if provided cancellationToken is already canceled. #5334
Conversation
…Token is already canceled Update NSUrlSessionHandler to cancel request if provided cancellationToken is already canceled. An already cancelled request is no more sent and the task nicely canceled. It fix this issue xamarin#5333 on my tests.
Thanks for the contribution! As this is not my area of expertise, we'll have to wait for others with more experience in networking to land this. Given that many are on Christmas break, it may be a week or so until everyone is back. Apologies for the delay and thanks again. |
build |
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.
Please provide more explanation on how you think this fix the issue and how it can be verified. Thanks!
dataTask.Resume (); | ||
|
||
|
||
if (!cancellationToken.IsCancellationRequested) { |
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.
That seems to always be hit (e.g. adding an else
and a breakpoint or some Console.WriteLine
is never hit).
Also I can reproduce the hang locally, with the supplied test case, even with the patch applied. Now it works, some times, but it's hard to say if the different timings makes it more or less likely (or if it's purely random).
Considering the Cancel
is a no-op I do not think this change is fixing the issue.
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.
What is always hit? I use the reproduce steps provided in the referred bug and with this it does not happens. Be sure to use a small timeout btw
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.
if (!cancellationToken.IsCancellationRequested) {
is always evaluated as true
when testing, so in effect that change is a no op
I used different times and the results varies (hangs or none) but it's to really correlated to the times.
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.
Ok I get it : do you want me to remove this line or can we consider that in theory the cancellationToken could be already cancelled as you don't know from where it comes from ?
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 think the line can stay, it's logic not to add it if already cancelled.
However this makes both of your original changes no ops which means nothing is solved. If you're getting different results it's because the test case is a bit too random in its results (not your fault but it makes things harder to see if the problem is fixed).
If this is related to the mono thread pool issue (like you cross-linked to) then it's unlikely that ay change in the handler code will be able to fix the issue.
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.
You are right, I have made more investigation and it seems that this is another behavior which causes the issue : #5334 (comment)
Build failure Test results1 tests failed, 0 tests skipped, 80 tests passed.Failed tests
|
Put the CreateDataTask call inside the inflightRequestsLock to be sure that NSUrlSessionHandlerDelegate::DidCompleteWithError will get it if the task is created immediatly "faulted" by iOS.
@spouliot I have made more tests on my side wit the provided sample for the issue. I have found out that ios can also create a "faulted task" when calling session.CreateDataTask. In this case, the inflightRequests does not contains the created task when the NSUrlSessionHandlerDelegate is called (it's 'DidCompleteWithError' method). To fix this, I added the creation of the task in the inflightRequestsLock and then the data will be for sure in it. When not's done, it seems that in SendAsync the How can I help you more ? |
if (dataTask.State == NSUrlSessionTaskState.Suspended) | ||
} | ||
|
||
if (dataTask != null && dataTask.State == NSUrlSessionTaskState.Suspended) |
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.
why the addition of dataTask != null
? have you run into that case ?
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.
it happens if cancellationToken.IsCancellationRequested which could theorically happen.
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.
no it can't since you moved that block (if
) inside the condition (you mentioned)
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.
OMG you are right sorry for being this blind reading my own code ! I removed the null check.
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.
Is it ok for you @spouliot ? How can I help you on this PR ? :)
remove useless null check
@jonathanantoine @spouliot let me poke the test application and will try to get back to you asap (sorry for the delay, xmas break). |
@spouliot @jonathanantoine so, I don't how do you feel about this approach, but it is something that I have tested (I quickly wrote a patch that you can find here) and seems to work, or at least, do not hang the application. Let me first explain the train of tough:
The ideal fix would be that we do not have an issue with the thread pool, but this is not going to be something we can fix, at least in the sort time. The new ideal fix, or at least, what I though it would be a good compromise, would be to cancel those request that are inflight. We could do so by listening to the notification center, register a callback that will try to set the inflight sources to be canceled, that will trigger the registration of the cancellation token and should clean the resources. At this point, our API user will know that the task was cancelled and that he will have to deal with that, if a developer does not want the task to be canceled when the app is in the background, simply point to the background session. Regarding the PR, I'm +1 on not adding a task if the cancelation token tells us. |
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.
+1 on adding the if statement, but I don't believe that it does fix the issue. Please read my comment for a possible workaround (cancelling when being notified of the app going to the background).
@mandel-macaque thanks for your review. I don't understand the change you want as the "if" statement is present and used. |
@jonathanantoine take a look at the gist I provided. while the check for the cancelation is indeed needed, the addition is not fixing the underlaying issue. As I mentioned on This way you will always be in a known state and the state machine will not hang/block. |
Hey @jonathanantoine it turns out the issue you ran into runs a bit deeper than first suspected. #5511 for example. @mandel-macaque started with your work and extended it to cover that case as well, which is now #5557. Sorry for the long delay in responding to this PR, we wanted to make sure we had this nailed down before we closed your PR. Thanks for the contribution and being a part of fixing this fun network issue. |
Perfect, thanks a lot for your work ! |
Update NSUrlSessionHandler to cancel request if provided cancellationToken is already canceled.
An already cancelled request is no more sent and the task nicely canceled.
It fix this issue #5333 on my tests.