-
Notifications
You must be signed in to change notification settings - Fork 743
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
Fix for concurrent fetching bugs #1227
Conversation
let taskData = TaskData(rawCompletion: rawTaskCompletionHandler, | ||
completionBlock: completion) | ||
|
||
self.tasks.mutate { $0[task.taskIdentifier] = taskData } |
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 would create some "insert" that checks if ID is already there just for sanity sake :)
or have something like
self.tasks.mutate {
// assert if id is in $0
$0[task.taskIdentifier] = taskData
}
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.
generally i'd agree with this but I did get confirmation that the issue was my misuse of locks that was causing the problem with the task data failing to increment. If this isn't working now, it's a clear URLSession
bug.
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 also was able to validate that with the changes the number increments properly)
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.
the problem might arise if someone changes locking logic and will reintroduce bug. Without any checking error will be just "swallowed" until someone reports it :)
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.
Fair, though I think that's probably better to check through tests than an assertion
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.
updated the test with concurrentPerform
to validate that all task ids created are unique.
self.datas.value[dataTask.taskIdentifier]?.append(data) | ||
self.tasks.mutate { | ||
guard let taskData = $0[dataTask.taskIdentifier] else { | ||
return |
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.
would personally add some assert as it "must" be here
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've been really trying to avoid asserts in library code here, but I do think it's reasonable for the didReceive data
method.
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.
assert is not great for reason that they don't play nicely with tests... but just ignoring possible error is not nice...
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.
yeah, this is where not being able to throw an error is really annoying. I did add the assert to the didReceive data
method.
@@ -0,0 +1,25 @@ | |||
import Foundation | |||
|
|||
public class TaskData { |
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.
wonder if you need do some "cleanup" on deinit (like calling completion handlers)
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.
There's no way to tell if the completion handlers have already been called, so I don't think that's a great idea in this case.
…session during a test
…o have made that actually work properly
3445ac4
to
e58853d
Compare
OK, I'm gonna merge this - @RolandasRazma thanks for the review! |
any time :) |
@prakash8393 Can you please open a new issue on this so we can figure out what's going on? It'd also help to see code from the place you're calling it, so we can see if maybe something's getting hit by ARC. |
Thanks @designatednerd it worked . thanks for your response :) |
So, turns out a fairly large assumption I made (URLSessionTask
identifers are unique) is basically incorrect in a sufficiently concurrent set of requests. This means when using the task identifier as a key in a dictionary, you may wind up with multiple requests having the same task identifier, and the dictionaries lose their mind.This PR updates the underlying dictionaries inURLSessionClient
to key off theURLSessionTask
itself rather than just the identifier.This is a partial fix for #1210 - there's still something going on there that I can't put my finger on, but I wanted to at least get this merged for the next version since it does fix what is definitely incorrect behaviorWelp, looks like our locking behavior wasn't doing what I was expecting it to do, and it was having all sorts of weird side effects, including effing up the task identifier generation - shout out to @davedelong and @bdash for spotting what I was doing wrong and offering better suggestions.
This should now be an actual fix for #1210 and/or #1226.