Translate TransactionCanceledException to ContestedOptimisticLockException in Accounts#changeNumber
This commit is contained in:
parent
84af984c4b
commit
2d4d37f96a
|
@ -429,6 +429,24 @@ public class Accounts extends AbstractDynamoDbStore {
|
||||||
succeeded = true;
|
succeeded = true;
|
||||||
} catch (final JsonProcessingException e) {
|
} catch (final JsonProcessingException e) {
|
||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
|
} catch (final TransactionCanceledException e) {
|
||||||
|
if (e.hasCancellationReasons() && e.cancellationReasons().size() == 6) {
|
||||||
|
// the cancellation reasons map to the write items:
|
||||||
|
// 0. phone number constraint delete - no conditions
|
||||||
|
// 1. phone number constraint put - conditional on the key not existing (it is deleted by 0)
|
||||||
|
// 2. pni constraint delete - no conditions
|
||||||
|
// 3. pni constraint put - conditional on the key not existing (it is deleted by 2)
|
||||||
|
// 4. deleted accounts delete - no conditions
|
||||||
|
// 5. account update - conditional on #version = :version
|
||||||
|
if (CONDITIONAL_CHECK_FAILED.equals(e.cancellationReasons().get(5).code())) {
|
||||||
|
// the #version = :version condition failed, which indicates a concurrent update
|
||||||
|
throw new ContestedOptimisticLockException();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("Unexpected cancellation reasons: {}", e.cancellationReasons());
|
||||||
|
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
if (!succeeded) {
|
if (!succeeded) {
|
||||||
account.setNumber(originalNumber, originalPni);
|
account.setNumber(originalNumber, originalPni);
|
||||||
|
|
|
@ -885,6 +885,41 @@ class AccountsTest {
|
||||||
assertThrows(TransactionCanceledException.class, () -> accounts.changeNumber(account, targetNumber, existingPhoneNumberIdentifier, Optional.empty(), Collections.emptyList()));
|
assertThrows(TransactionCanceledException.class, () -> accounts.changeNumber(account, targetNumber, existingPhoneNumberIdentifier, Optional.empty(), Collections.emptyList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChangeNumberContestedOptimisticLock() {
|
||||||
|
final String originalNumber = "+14151112222";
|
||||||
|
final String targetNumber = "+14151113333";
|
||||||
|
|
||||||
|
final UUID originalPni = UUID.randomUUID();
|
||||||
|
final UUID targetPni = UUID.randomUUID();
|
||||||
|
|
||||||
|
final Device device = generateDevice(DEVICE_ID_1);
|
||||||
|
final Account firstAccountInstance = generateAccount(originalNumber, UUID.randomUUID(), originalPni,
|
||||||
|
List.of(device));
|
||||||
|
|
||||||
|
createAccount(firstAccountInstance);
|
||||||
|
|
||||||
|
final Account secondAccountInstance = accounts.getByAccountIdentifier(firstAccountInstance.getUuid()).orElseThrow();
|
||||||
|
|
||||||
|
// update via the first instance, which will update the version
|
||||||
|
firstAccountInstance.setCurrentProfileVersion("1");
|
||||||
|
accounts.update(firstAccountInstance);
|
||||||
|
|
||||||
|
assertThrows(ContestedOptimisticLockException.class,
|
||||||
|
() -> accounts.changeNumber(secondAccountInstance, targetNumber, targetPni, Optional.empty(),
|
||||||
|
Collections.emptyList()), "Second account instance has stale version");
|
||||||
|
|
||||||
|
final Account refreshedAccountInstance = accounts.getByAccountIdentifier(firstAccountInstance.getUuid())
|
||||||
|
.orElseThrow();
|
||||||
|
accounts.changeNumber(refreshedAccountInstance, targetNumber, targetPni, Optional.empty(),
|
||||||
|
Collections.emptyList());
|
||||||
|
|
||||||
|
assertPhoneNumberConstraintDoesNotExist(originalNumber);
|
||||||
|
assertPhoneNumberIdentifierConstraintDoesNotExist(originalPni);
|
||||||
|
assertPhoneNumberConstraintExists(targetNumber, firstAccountInstance.getUuid());
|
||||||
|
assertPhoneNumberIdentifierConstraintExists(targetPni, firstAccountInstance.getUuid());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSwitchUsernameHashes() {
|
void testSwitchUsernameHashes() {
|
||||||
final Account account = generateAccount("+18005551234", UUID.randomUUID(), UUID.randomUUID());
|
final Account account = generateAccount("+18005551234", UUID.randomUUID(), UUID.randomUUID());
|
||||||
|
|
Loading…
Reference in New Issue