Skip to content

Commit 4625899

Browse files
authored
Make backoff account for already-elapsed time. (#1712)
* Make backoff account for already-elapsed time. [Port of firebase/firebase-js-sdk#1132]
1 parent 2f6ff23 commit 4625899

File tree

1 file changed

+28
-4
lines changed

1 file changed

+28
-4
lines changed

Firestore/Source/Remote/FSTExponentialBackoff.mm

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <random>
2020

21+
#import "Firestore/Source/Util/FSTClasses.h"
2122
#import "Firestore/Source/Util/FSTDispatchQueue.h"
2223

2324
#include "Firestore/core/src/firebase/firestore/util/log.h"
@@ -33,6 +34,7 @@ @interface FSTExponentialBackoff ()
3334
@property(nonatomic) NSTimeInterval initialDelay;
3435
@property(nonatomic) NSTimeInterval maxDelay;
3536
@property(nonatomic) NSTimeInterval currentBase;
37+
@property(nonatomic) NSTimeInterval lastAttemptTime;
3638
@property(nonatomic, strong, nullable) FSTDelayedCallback *timerCallback;
3739
@end
3840

@@ -51,6 +53,7 @@ - (instancetype)initWithDispatchQueue:(FSTDispatchQueue *)dispatchQueue
5153
_initialDelay = initialDelay;
5254
_backoffFactor = backoffFactor;
5355
_maxDelay = maxDelay;
56+
_lastAttemptTime = [[NSDate date] timeIntervalSince1970];
5457

5558
[self reset];
5659
}
@@ -69,13 +72,34 @@ - (void)backoffAndRunBlock:(void (^)(void))block {
6972
[self cancel];
7073

7174
// First schedule the block using the current base (which may be 0 and should be honored as such).
72-
NSTimeInterval delayWithJitter = _currentBase + [self jitterDelay];
75+
NSTimeInterval desiredDelayWithJitter = _currentBase + [self jitterDelay];
76+
77+
// Guard against lastAttemptTime being in the future due to a clock change.
78+
NSTimeInterval delaySoFar = MAX(0, [[NSDate date] timeIntervalSince1970] - self.lastAttemptTime);
79+
80+
// Guard against the backoff delay already being past.
81+
NSTimeInterval remainingDelay = MAX(0, desiredDelayWithJitter - delaySoFar);
82+
7383
if (_currentBase > 0) {
74-
LOG_DEBUG("Backing off for %s seconds (base delay: %s seconds)", delayWithJitter, _currentBase);
84+
LOG_DEBUG(
85+
"Backing off for %s seconds ("
86+
"base delay: %s seconds, "
87+
"delay with jitter: %s seconds, "
88+
"last attempt: %s seconds ago)",
89+
remainingDelay, _currentBase, desiredDelayWithJitter, delaySoFar);
7590
}
7691

77-
self.timerCallback =
78-
[self.dispatchQueue dispatchAfterDelay:delayWithJitter timerID:self.timerID block:block];
92+
FSTWeakify(self);
93+
self.timerCallback = [self.dispatchQueue
94+
dispatchAfterDelay:remainingDelay
95+
timerID:self.timerID
96+
block:^{
97+
FSTStrongify(self);
98+
if (self) {
99+
self.lastAttemptTime = [[NSDate date] timeIntervalSince1970];
100+
block();
101+
}
102+
}];
79103

80104
// Apply backoff factor to determine next delay and ensure it is within bounds.
81105
_currentBase *= _backoffFactor;

0 commit comments

Comments
 (0)