Skip to content
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

Merged
merged 14 commits into from
May 27, 2020
Merged

Fix for concurrent fetching bugs #1227

merged 14 commits into from
May 27, 2020

Conversation

designatednerd
Copy link
Contributor

@designatednerd designatednerd commented May 26, 2020

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 in URLSessionClient to key off the URLSessionTask 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 behavior

Welp, 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.

@designatednerd designatednerd changed the title Partial fix for multiple fetch Fix for concurrent fetching bugs May 26, 2020
let taskData = TaskData(rawCompletion: rawTaskCompletionHandler,
completionBlock: completion)

self.tasks.mutate { $0[task.taskIdentifier] = taskData }
Copy link
Contributor

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
}

Copy link
Contributor Author

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.

Copy link
Contributor Author

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)

Copy link
Contributor

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 :)

Copy link
Contributor Author

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

Copy link
Contributor Author

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
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor

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...

Copy link
Contributor Author

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 {
Copy link
Contributor

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)

Copy link
Contributor Author

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.

@designatednerd
Copy link
Contributor Author

OK, I'm gonna merge this - @RolandasRazma thanks for the review!

@designatednerd designatednerd merged commit f64b3f6 into master May 27, 2020
@designatednerd designatednerd added this to the Next Release milestone May 27, 2020
@designatednerd designatednerd deleted the fix/multifetch branch May 27, 2020 23:36
@RolandasRazma
Copy link
Contributor

RolandasRazma commented May 29, 2020

@RolandasRazma thanks for the review!

any time :)

@designatednerd
Copy link
Contributor Author

@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.

@prakash8393
Copy link

@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 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants