First of all, please be aware that this question is closely related to this other one. I have a springboot application with a @Transactional(propagation=Propagation.REQUIRES_NEW)
CreateUser
service. Then, I have @DataJpaTest
integration test in which I intend to test the system's behavior under a highly concurrent scenario. However, the test is not passing and the problem seems to be related with the fact that spawned threads (I'm using a FixedThreadPool
with 10 threads) cannot see each other's DB modifications. As far as I know, every @DataJpaTest
creates its own transaction, and I tried to create a new transaction for each concurrent executed task without any success so far...
Could someone please help with this?
SpringBoot Application:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
// ...
@Bean
@Transactional(propagation = Propagation.REQUIRES_NEW)
public CreateUser createUserService(@Qualifier("JpaUserRepository") UserRepository userRepository,
@Qualifier("JpaReferralRepository") ReferralRepository referralRepository,
RegisterReferredUser registerReferredUser) {
return new CreateUser(userRepository, referralRepository, registerReferredUser);
}
}
Test:
@DataJpaTest(includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Repository.class))
public class JpaTest {
// ...
@Test
void createUser_shouldWorksProperlyUnderConcurrentExecution() throws InterruptedException {
EntityManager entityManager = this.entityManager.getEntityManager();
ExecutorService executor = Executors.newFixedThreadPool(10);
EmailAddress referrerUserEmail = EmailAddress.of("john.doe@sample.com");
User referrerUser = createUser.execute(new CreateUserCommand(referrerUserEmail.getValue(), null));
String referralCode = referrerUser.getReferralCode().getValue();
entityManager.getTransaction().commit();
int maxIterations = 1000;
for (int i = 0; i < maxIterations; i++) {
int emailSeed = i;
executor.submit(() -> {
// I'd like to start a new transaction for each concurrent executed task here
createUser.execute(new CreateUserCommand(anEmailAddress(emailSeed), referralCode));
});
}
executor.shutdown();
if (!executor.awaitTermination(20, TimeUnit.SECONDS)) {
fail("Executor didn't finish in time");
}
assertThat(this.entityManager.getEntityManager().createQuery("from JpaUser").getResultList().size())
.isEqualTo(maxIterations + 1);
referrerUser = getUser.execute(referrerUser.getId());
assertThat(referrerUser.getRewardsCounter()).isEqualTo(RewardsCounter.ZERO);
assertThat(referrerUser.getCredit()).isEqualTo(Credit.of(1000));
}
Aucun commentaire:
Enregistrer un commentaire