Skip to content

Commit 0593693

Browse files
author
Michael Lehenbauer
committed
Make C++ exponential backoff account for already-elapsed time.
[Port of firebase/firebase-js-sdk#1132]
1 parent 6542b46 commit 0593693

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

Firestore/core/src/firebase/firestore/remote/exponential_backoff.cc

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "Firestore/core/src/firebase/firestore/remote/exponential_backoff.h"
1818

19+
#include <algorithm>
1920
#include <random>
2021
#include <utility>
2122

@@ -39,7 +40,8 @@ ExponentialBackoff::ExponentialBackoff(AsyncQueue* queue,
3940
timer_id_{timer_id},
4041
backoff_factor_{backoff_factor},
4142
initial_delay_{initial_delay},
42-
max_delay_{max_delay} {
43+
max_delay_{max_delay},
44+
last_attempt_time_{chr::steady_clock::now()} {
4345
HARD_ASSERT(queue, "Queue can't be null");
4446

4547
HARD_ASSERT(backoff_factor >= 1.0, "Backoff factor must be at least 1");
@@ -55,13 +57,26 @@ void ExponentialBackoff::BackoffAndRun(AsyncQueue::Operation&& operation) {
5557

5658
// First schedule the block using the current base (which may be 0 and should
5759
// 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());
6277
}
6378

64-
delayed_operation_ = queue_->EnqueueAfterDelay(delay_with_jitter, timer_id_,
79+
delayed_operation_ = queue_->EnqueueAfterDelay(remaining_delay, timer_id_,
6580
std::move(operation));
6681

6782
// Apply backoff factor to determine next delay, but ensure it is within

Firestore/core/src/firebase/firestore/remote/exponential_backoff.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ namespace firebase {
2626
namespace firestore {
2727
namespace remote {
2828

29+
namespace chr = std::chrono;
30+
2931
/**
3032
*
3133
* A helper for running delayed operations following an exponential backoff
@@ -107,6 +109,7 @@ class ExponentialBackoff {
107109
const Milliseconds initial_delay_;
108110
const Milliseconds max_delay_;
109111
util::SecureRandom secure_random_;
112+
chr::time_point<chr::steady_clock> last_attempt_time_;
110113
};
111114

112115
} // namespace remote

0 commit comments

Comments
 (0)