Bump the number of retries in transaction failures and add skew (#2699)

This can potentially help even more with serializable transaction
failures (optimistic locking exceptions, which are expected to occur
somewhat frequently).

With six attempts, we will sleep at most five times, for
100+200+400+800+1600 ms each, for a total of at most 3.1 seconds (much
less than the EPP maximum which I believe (?) to be 30 seconds.

In addition, we add a 20% skew in an attempt to spread out
possibly-conflicting transaction retries.
This commit is contained in:
gbrodman
2025-03-21 19:47:55 +00:00
committed by GitHub
parent ed33c7424d
commit daa56e6d85
3 changed files with 15 additions and 10 deletions
@@ -86,7 +86,7 @@ import org.joda.time.DateTime;
public class JpaTransactionManagerImpl implements JpaTransactionManager {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Retrier retrier = new Retrier(new SystemSleeper(), 3);
private static final Retrier retrier = new Retrier(new SystemSleeper(), 6);
private static final String NESTED_TRANSACTION_MESSAGE =
"Nested transaction detected. Try refactoring to avoid nested transactions. If unachievable,"
+ " use reTransact() in nested transactions";
@@ -293,11 +293,11 @@ class JpaTransactionManagerImplTest {
assertThrows(
OptimisticLockException.class,
() -> spyJpaTm.transact(() -> spyJpaTm.delete(theEntityKey)));
verify(spyJpaTm, times(3)).delete(theEntityKey);
verify(spyJpaTm, times(6)).delete(theEntityKey);
assertThrows(
OptimisticLockException.class,
() -> spyJpaTm.transact(() -> spyJpaTm.delete(theEntityKey)));
verify(spyJpaTm, times(6)).delete(theEntityKey);
verify(spyJpaTm, times(12)).delete(theEntityKey);
}
@Test
@@ -355,10 +355,10 @@ class JpaTransactionManagerImplTest {
spyJpaTm.transact(() -> spyJpaTm.insert(theEntity));
assertThrows(
RuntimeException.class, () -> spyJpaTm.transact(() -> spyJpaTm.delete(theEntityKey)));
verify(spyJpaTm, times(3)).delete(theEntityKey);
verify(spyJpaTm, times(6)).delete(theEntityKey);
assertThrows(
RuntimeException.class, () -> spyJpaTm.transact(() -> spyJpaTm.delete(theEntityKey)));
verify(spyJpaTm, times(6)).delete(theEntityKey);
verify(spyJpaTm, times(12)).delete(theEntityKey);
}
@Test
@@ -759,11 +759,11 @@ class JpaTransactionManagerImplTest {
spyJpaTm.transact(
() -> {
spyJpaTm.exists(theEntity);
spyJpaTm.transact(() -> spyJpaTm.delete(theEntityKey));
spyJpaTm.delete(theEntityKey);
}));
verify(spyJpaTm, times(3)).exists(theEntity);
verify(spyJpaTm, times(3)).delete(theEntityKey);
verify(spyJpaTm, times(6)).exists(theEntity);
verify(spyJpaTm, times(6)).delete(theEntityKey);
}
private static void insertPerson(int age) {