Skip to content

Commit 38a7b1f

Browse files
author
Brian Chen
authored
Standardize transaction retries to attempts (#8314)
1 parent 75ec496 commit 38a7b1f

File tree

3 files changed

+45
-6
lines changed

3 files changed

+45
-6
lines changed

Firestore/Example/Tests/Integration/FSTTransactionTests.mm

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,45 @@ - (void)testDoesNotRetryOnPermanentError {
649649
[self awaitExpectations];
650650
}
651651

652+
- (void)testMakesDefaultMaxAttempts {
653+
FIRFirestore *firestore = [self firestore];
654+
FIRDocumentReference *doc1 = [[firestore collectionWithPath:@"counters"] documentWithAutoID];
655+
auto counter = std::make_shared<std::atomic_int>(0);
656+
657+
[self writeDocumentRef:doc1 data:@{@"count" : @(15.0)}];
658+
659+
// Skip backoff delays.
660+
[firestore workerQueue]->SkipDelaysForTimerId(TimerId::RetryTransaction);
661+
662+
XCTestExpectation *expectation = [self expectationWithDescription:@"transaction"];
663+
[firestore
664+
runTransactionWithBlock:^id _Nullable(FIRTransaction *transaction, NSError **error) {
665+
++(*counter);
666+
// Get the first doc.
667+
[transaction getDocument:doc1 error:error];
668+
XCTAssertNil(*error);
669+
// Do a write outside of the transaction to cause the transaction to fail.
670+
dispatch_semaphore_t writeSemaphore = dispatch_semaphore_create(0);
671+
int newValue = 1234 + counter->load();
672+
[doc1 setData:@{
673+
@"count" : @(newValue)
674+
}
675+
completion:^(NSError *) {
676+
dispatch_semaphore_signal(writeSemaphore);
677+
}];
678+
// We can block on it, because transactions run on a background queue.
679+
dispatch_semaphore_wait(writeSemaphore, DISPATCH_TIME_FOREVER);
680+
return nil;
681+
}
682+
completion:^(id, NSError *_Nullable error) {
683+
[expectation fulfill];
684+
XCTAssertNotNil(error);
685+
XCTAssertEqual(error.code, FIRFirestoreErrorCodeFailedPrecondition);
686+
XCTAssertEqual(counter->load(), 5);
687+
}];
688+
[self awaitExpectations];
689+
}
690+
652691
- (void)testSuccessWithNoTransactionOperations {
653692
FIRFirestore *firestore = [self firestore];
654693
XCTestExpectation *expectation = [self expectationWithDescription:@"transaction"];

Firestore/core/src/core/transaction_runner.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ using util::AsyncQueue;
3131
using util::Status;
3232
using util::TimerId;
3333

34-
/** Maximum number of times a transaction can be retried before failing. */
35-
constexpr int kRetryCount = 5;
34+
/** Maximum number of times a transaction can be attempted before failing. */
35+
constexpr int kMaxAttemptsCount = 5;
3636

3737
bool IsRetryableTransactionError(const util::Status& error) {
3838
// In transactions, the backend will fail outdated reads with
@@ -54,11 +54,12 @@ TransactionRunner::TransactionRunner(const std::shared_ptr<AsyncQueue>& queue,
5454
update_callback_{std::move(update_callback)},
5555
result_callback_{std::move(result_callback)},
5656
backoff_{queue_, TimerId::RetryTransaction},
57-
retries_left_{kRetryCount} {
57+
attempts_remaining_{kMaxAttemptsCount} {
5858
}
5959

6060
void TransactionRunner::Run() {
6161
queue_->VerifyIsCurrentQueue();
62+
attempts_remaining_ -= 1;
6263

6364
auto shared_this = this->shared_from_this();
6465
backoff_.BackoffAndRun([shared_this] {
@@ -96,9 +97,8 @@ void TransactionRunner::DispatchResult(
9697

9798
void TransactionRunner::HandleTransactionError(
9899
const std::shared_ptr<Transaction>& transaction, Status status) {
99-
if (retries_left_ > 0 && IsRetryableTransactionError(status) &&
100+
if (attempts_remaining_ > 0 && IsRetryableTransactionError(status) &&
100101
!transaction->IsPermanentlyFailed()) {
101-
retries_left_ -= 1;
102102
Run();
103103
} else {
104104
result_callback_(std::move(status));

Firestore/core/src/core/transaction_runner.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class TransactionRunner
6767
core::TransactionUpdateCallback update_callback_;
6868
core::TransactionResultCallback result_callback_;
6969
remote::ExponentialBackoff backoff_;
70-
int retries_left_;
70+
int attempts_remaining_;
7171
};
7272

7373
} // namespace core

0 commit comments

Comments
 (0)