16
16
17
17
#include " Firestore/core/src/firebase/firestore/remote/exponential_backoff.h"
18
18
19
+ #include < algorithm>
19
20
#include < random>
20
21
#include < utility>
21
22
@@ -39,7 +40,8 @@ ExponentialBackoff::ExponentialBackoff(AsyncQueue* queue,
39
40
timer_id_{timer_id},
40
41
backoff_factor_{backoff_factor},
41
42
initial_delay_{initial_delay},
42
- max_delay_{max_delay} {
43
+ max_delay_{max_delay},
44
+ last_attempt_time_{chr::steady_clock::now ()} {
43
45
HARD_ASSERT (queue, " Queue can't be null" );
44
46
45
47
HARD_ASSERT (backoff_factor >= 1.0 , " Backoff factor must be at least 1" );
@@ -55,13 +57,26 @@ void ExponentialBackoff::BackoffAndRun(AsyncQueue::Operation&& operation) {
55
57
56
58
// First schedule the block using the current base (which may be 0 and should
57
59
// be honored as such).
58
- Milliseconds delay_with_jitter = current_base_ + GetDelayWithJitter ();
59
- if (delay_with_jitter.count () > 0 ) {
60
- LOG_DEBUG (" Backing off for %s milliseconds (base delay: %s milliseconds)" ,
61
- delay_with_jitter.count (), current_base_.count ());
60
+ Milliseconds desired_delay_with_jitter = current_base_ + GetDelayWithJitter ();
61
+
62
+ Milliseconds delay_so_far = chr::duration_cast<Milliseconds>(
63
+ chr::steady_clock::now () - last_attempt_time_);
64
+
65
+ // Guard against the backoff delay already being past.
66
+ auto remaining_delay =
67
+ max (Milliseconds::zero (), desired_delay_with_jitter - delay_so_far);
68
+
69
+ if (current_base_.count () > 0 ) {
70
+ LOG_DEBUG (
71
+ " Backing off for %s ms "
72
+ " (base delay: %s ms, "
73
+ " delay with jitter: %s ms, "
74
+ " last attempt: %s ms ago)" ,
75
+ remaining_delay.count (), current_base_.count (),
76
+ desired_delay_with_jitter.count (), delay_so_far.count ());
62
77
}
63
78
64
- delayed_operation_ = queue_->EnqueueAfterDelay (delay_with_jitter , timer_id_,
79
+ delayed_operation_ = queue_->EnqueueAfterDelay (remaining_delay , timer_id_,
65
80
std::move (operation));
66
81
67
82
// Apply backoff factor to determine next delay, but ensure it is within
0 commit comments