Treat transaction conflicts during transactional account updates as contested optimistic locks
This commit is contained in:
parent
417d99a17e
commit
cca747a1f6
|
@ -887,7 +887,14 @@ public class Accounts extends AbstractDynamoDbStore {
|
||||||
final Throwable unwrapped = ExceptionUtils.unwrap(throwable);
|
final Throwable unwrapped = ExceptionUtils.unwrap(throwable);
|
||||||
|
|
||||||
if (unwrapped instanceof TransactionCanceledException transactionCanceledException) {
|
if (unwrapped instanceof TransactionCanceledException transactionCanceledException) {
|
||||||
if ("ConditionalCheckFailed".equals(transactionCanceledException.cancellationReasons().get(0).code())) {
|
if (CONDITIONAL_CHECK_FAILED.equals(transactionCanceledException.cancellationReasons().get(0).code())) {
|
||||||
|
throw new ContestedOptimisticLockException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactionCanceledException.cancellationReasons()
|
||||||
|
.stream()
|
||||||
|
.anyMatch(reason -> TRANSACTION_CONFLICT.equals(reason.code()))) {
|
||||||
|
|
||||||
throw new ContestedOptimisticLockException();
|
throw new ContestedOptimisticLockException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ import reactor.core.scheduler.Schedulers;
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||||
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
||||||
|
import software.amazon.awssdk.services.dynamodb.model.CancellationReason;
|
||||||
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
|
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
|
||||||
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
|
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
|
||||||
import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
|
import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
|
||||||
|
@ -627,6 +628,32 @@ class AccountsTest {
|
||||||
assertTrue(completionException.getCause() instanceof ContestedOptimisticLockException);
|
assertTrue(completionException.getCause() instanceof ContestedOptimisticLockException);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUpdateTransactionallyWithMockTransactionConflictException() {
|
||||||
|
final DynamoDbAsyncClient dynamoDbAsyncClient = mock(DynamoDbAsyncClient.class);
|
||||||
|
|
||||||
|
accounts = new Accounts(mock(DynamoDbClient.class),
|
||||||
|
dynamoDbAsyncClient,
|
||||||
|
Tables.ACCOUNTS.tableName(),
|
||||||
|
Tables.NUMBERS.tableName(),
|
||||||
|
Tables.PNI_ASSIGNMENTS.tableName(),
|
||||||
|
Tables.USERNAMES.tableName(),
|
||||||
|
Tables.DELETED_ACCOUNTS.tableName());
|
||||||
|
|
||||||
|
when(dynamoDbAsyncClient.transactWriteItems(any(TransactWriteItemsRequest.class)))
|
||||||
|
.thenReturn(CompletableFuture.failedFuture(TransactionCanceledException.builder()
|
||||||
|
.cancellationReasons(CancellationReason.builder()
|
||||||
|
.code("TransactionConflict")
|
||||||
|
.build())
|
||||||
|
.build()));
|
||||||
|
|
||||||
|
Account account = generateAccount("+14151112222", UUID.randomUUID(), UUID.randomUUID());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> accounts.updateTransactionallyAsync(account, Collections.emptyList()).toCompletableFuture().join())
|
||||||
|
.isInstanceOfAny(CompletionException.class)
|
||||||
|
.hasCauseInstanceOf(ContestedOptimisticLockException.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetAll() {
|
void testGetAll() {
|
||||||
final List<Account> expectedAccounts = new ArrayList<>();
|
final List<Account> expectedAccounts = new ArrayList<>();
|
||||||
|
|
Loading…
Reference in New Issue