Skip to content

Fix for concurrent fetching bugs#1227

Merged
designatednerd merged 14 commits intomasterfrom
fix/multifetch
May 27, 2020
Merged

Fix for concurrent fetching bugs#1227
designatednerd merged 14 commits intomasterfrom
fix/multifetch

Conversation

@designatednerd
Copy link
Copy Markdown
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
Comment thread Sources/Apollo/URLSessionClient.swift Outdated
let taskData = TaskData(rawCompletion: rawTaskCompletionHandler,
completionBlock: completion)

self.tasks.mutate { $0[task.taskIdentifier] = taskData }
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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.

Comment thread Sources/Apollo/URLSessionClient.swift
@designatednerd
Copy link
Copy Markdown
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
Copy Markdown
Contributor

RolandasRazma commented May 29, 2020

@RolandasRazma thanks for the review!

any time :)

@designatednerd
Copy link
Copy Markdown
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
Copy Markdown

@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