An existing (ugly) integration test send and wait a JMS message locally (ActiveMq). The wait here does (an ugly) polling (timeout 60s) to get a Todo row inserted by the consumer of the JMS.
The test is flacky meaning the polling exceeds the 60s for sometimes. I activated the transactions commit to see at which time spring initiates a commit, and I see that for all failed test the commit was initiated just too early before the timeout of 60s (because the work that the consumer needs to do is about 1.5s).
So the 60 second is already more enough to get a chance to have the result that is inserted and commited by the consumer.
What could be the possible reasons that sometimes the polling is getting the data just before the time out of 60s and sometimes it does not get it even more than 60s whereas the elapsed time of the consumer to consume the message is about 1.5s?
I know this is not the best way to do a perf test and I would not dare to change the test, just I would like what are the possible reasons that this sometimes fail.
@Repository
public interface TodoRepository extends JpaRepository<Todo, String> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "1000"),
@QueryHint(name = "javax.persistence.query.timeout", value = "1000")})
@Query("select t from Todo t where t.key=?1")
Todo findAndLock(String key);
@Query("select t from Todo t where t.key=?1")
Todo find(String key);
}
@SpringBootTest
@Transactional // this is strange ....
class TodoJmsPerfTest {
@Autowired
TodoRepository todoRepository;
@Autowired
JmsTemplate jmsTemplate;
@Test
void sendAndWait() {
jmsTemplate.send("myQueue", s -> ....textMessage);
startPolling = System.currentTimeMillis();
while (!isFinished()) {
wait(startPolling);
}
}
private boolean isFinished() {
Todo t = todoRepository.find(myKey); // we know what is the value of the key
return t != null;
}
private wait(long startPolling) {
// still not reached 60s
if (startPolling + 60000L < currentTimeMillis()) {
Assertions.fail("timeout");
}
await().atMost(50L, TimeUnit.MILLISECONDS).await(); // wait for 50 millisecond before retry
}
}
public class TodoJmsConsumer {
@Autowired
TodoRepository todoRepository;
@Autowired
EntityManager entityManager;
@JmsListener(....)
@Transactional
public void receiveMessage(Message msg) {
// here extract info from message to create the Todo entity
Todo t = todoRepository.findAndLock(myKey);//same as in the test
if (t == null) {
Todo t = new Todo(...);
entityManager.persist(t);// I do not know why em here and not the repositoy...
}
}// this method takes 1.5s for te test.
}
The project is spring boot 2.7, h2, ActiveMq, Hibernate (level2Cache is activated).
Tried to activate much logs and nothing seems strange.
Sayros is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.