-
-
Notifications
You must be signed in to change notification settings - Fork 69
Removing random Int in the reconnection interval of ParseLiveQuery and added warning in playgrounds #208
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
Conversation
- mixed environment with both custom and server generated objectId not supported - ParseObject.fetch() returns empty object instead of .objectNotFound ParseError Removing random Int in the reconnection interval of ParseLiveQuery If socket is being open by user, there is no reason for delay -> Added boolean check
Codecov Report
@@ Coverage Diff @@
## main #208 +/- ##
==========================================
+ Coverage 82.76% 82.84% +0.07%
==========================================
Files 76 76
Lines 7242 7250 +8
==========================================
+ Hits 5994 6006 +12
+ Misses 1248 1244 -4
Continue to review full report at Codecov.
|
| var reconnectInterval: Int { | ||
| let min = NSDecimalNumber(decimal: Swift.min(30, pow(2, attempts) - 1)) | ||
| return Int.random(in: 0 ..< Int(truncating: min)) | ||
| return Int(truncating: min) |
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's the reason for changing this?
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.
As I mentioned here, I suspect a code race as the reconnectionInterval is mostly 0 for first two attempts and resumeTask() is deallocating the delegate with URLSession.liveQuery.delegates.removeValue(forKey: self.task)
Parse-Swift/Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift
Lines 229 to 249 in e3f51f4
| func resumeTask(completion: @escaping (Error?) -> Void) { | |
| synchronizationQueue.sync { | |
| switch self.task.state { | |
| case .suspended: | |
| task.resume() | |
| URLSession.liveQuery.delegates.removeValue(forKey: self.task) | |
| URLSession.liveQuery.delegates[self.task] = self | |
| completion(nil) | |
| case .completed, .canceling: | |
| URLSession.liveQuery.delegates.removeValue(forKey: self.task) | |
| task = URLSession.liveQuery.createTask(self.url) | |
| task.resume() | |
| URLSession.liveQuery.delegates[self.task] = self | |
| completion(nil) | |
| case .running: | |
| open(isUserWantsToConnect: false, completion: completion) | |
| @unknown default: | |
| break | |
| } | |
| } | |
| } |
Is there a reason for the random Int? Because without the random Int the LiveQuery reconnection seems to behave much more reproducible and is even reconnecting on server reset without holding the execution with a breakpoint.
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.
As I mentioned here, I suspect a code race as the reconnectionInterval is mostly 0 for first two attempts and resumeTask() is deallocating the delegate with URLSession.liveQuery.delegates.removeValue(forKey: self.task)
This will need more justification and discussion before a change like this can be accepted (you can open an issue to begin that discussion). The first few attempts should come out to zero because it's a random increasing interval that increases based on the amount of attempts, so zero the first 2-3 attempts makes sense and represents trying to reconnect immediately after disconnection.
Is there a reason for the random Int?
In networking you generally have some form of increasing backoff when attempting to reconnect. Imagine you had many user devices that were connected via LiveQuery. If they all were disconnected at the same time and then attempted to reconnect at the exact same intervals, you may run into a resource issue. If they all attempt to reconnect at slightly different times, you can stagger the reconnections and hopefully reconnect everyone.
I recommend changing this back to the original as even if there is a problem, this doesn't seem like the appropriate fix. The test case shows the randomInterval is doing what it's suppose to do. You can add a print statement to see the values if you want:
Parse-Swift/Tests/ParseSwiftTests/ParseLiveQueryTests.swift
Lines 506 to 518 in e3f51f4
| func testReconnectInterval() throws { | |
| guard let client = ParseLiveQuery.getDefault() else { | |
| XCTFail("Should be able to get client") | |
| return | |
| } | |
| for index in 0 ..< 50 { | |
| let time = client.reconnectInterval | |
| XCTAssertLessThan(time, 30) | |
| XCTAssertGreaterThan(time, -1) | |
| client.attempts += index | |
| } | |
| client.close() | |
| } |
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 zeros are the problem, you can make the following change:
let min = NSDecimalNumber(decimal: Swift.min(30, pow(2, attempts)))
return Int.random(in: 1 ..< Int(truncating: min))You will also need to change this line in the test to XCTAssertGreaterThan(time, 0) :
| XCTAssertGreaterThan(time, -1) |
You can try that with the recent updates in #209
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.
Sorry for misunderstanding, the 0 was my focus and I assumed that without the random Int it is still increasing backoff, so that was the reason for that change. But I tested your update #209 and I can confirm that it solved even better the reconnection issue that should this commit resolve.
|
|
||
| //: Asynchronously (preferred way) fetch this GameScore based on it's objectId alone. | ||
| scoreToFetch.fetch { result in | ||
| /*: Warning: server does return empty object {} instead of a ParseServer error `.objectNotFount` |
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.
nits, change .objectNotFount to .objectNotFound
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.
Change:
User
query.first()ofquery.find()
To: “Use query.first() or query.find()”
| switch result { | ||
| case .success(let fetchedScore): | ||
| print("Successfully fetched: \(fetchedScore)") | ||
| /*: Warning: server does return empty object {} instead of a ParseServer error `.objectNotFount` |
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.
same nits here
|
@lsmilek1 thanks for submitting your first PR! Don't forget to add a change log entry: https://github.com/parse-community/Parse-Swift/blob/main/CHANGELOG.md |
|
|
||
| //: Asynchronously (preferred way) fetch this GameScore based on it's objectId alone. | ||
| scoreToFetch.fetch { result in | ||
| /*: Warning: server does return empty object {} instead of a ParseServer error `.objectNotFount` |
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.
Change:
User
query.first()ofquery.find()
To: “Use query.first() or query.find()”
| /*: In Xcode, make sure you are building the "ParseSwift (macOS)" framework. | ||
| */ | ||
|
|
||
| /*: Warning: A mixed environment with both custom and server generated ObjectId |
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.
Change “ObjectId” to “objectId“
|
Closing this PR as there the LiveQuery reconnection is solved with #209. Thank you! |
Added warning in playgrounds related to:
Removing random Int in the reconnection interval of ParseLiveQuery: