问题
In one of the steps of my Spring Batch job, I'm trying to configure it so that when ObjectOptimisticLockingFailureException
happens, the step can be retried and hopefully the retry will work.
@Bean
public Step myStep(StaxEventItemReader<Response> staxEventResponseReader,
ItemWriter<Response> itemWriter,
ItemProcessor<? super Response, ? extends Response> responseProcessor) {
return stepBuilderFactory.get("myStep")
.<Response, Response>chunk(1)
.reader(staxEventResponseReader)
.processor(responseProcessor)
.writer(itemWriter)
//.faultTolerant().retryLimit(3).retry(Exception.class)
.build();
}
The logic of writer for the step is pretty simple: it tries to read a row from the database, and once it finds the row, it updates it. I was able to reproduce the ObjectOptimisticLockingFailureException
by setting a breakpoint right after the find method, manually bump the version
column for the row in database and commit it, then resume.
However, after uncommenting the retry definition in my step, no retries were attempted. After some debugging, it seems that the Spring retry logic is inside the chunk's transaction; but since the ObjectOptimisticLockingFailureException
is not thrown by my code in the writer, but by Spring's chunk transaction committing logic, no retries were attempted at all.
Chunk Transaction Begin
Begin Retry loop in FaultTolerantChunkProcessor.write()
Writer logic in my Step
End Retry loop
Chunk Transaction Commit - Throws ObjectOptimisticLockingFailureException
When I tried to explicitly throw ObjectOptimisticLockingFailureException
in my writer, the retry logic worked perfectly as expected. My questions are:
- How to make the retry logic work if the exception is not thrown from my writer code in the step, but by the time the chunk transaction is committed by Spring Batch?
- Another weird behavior is, when I manually cause the
ObjectOptimisticLockingFailureException
by bumping the version column in database, with the retry definition commented in the step, the final status of the step is FAILED which is expected. But with the retry definition uncommented, the final status of the step is COMPLETE. Why is that?
回答1:
- How to make the retry logic work if the exception is not thrown from my writer code in the step, but by the time the chunk transaction is committed by Spring Batch?
There is an open issue for that here: https://github.com/spring-projects/spring-batch/issues/1826. The workaround is to (try to anticipate and) throw any exception that might happen at the commit time in the writer. This is what you tried already and confirmed that works when you say When I tried to explicitly throw ObjectOptimisticLockingFailureException in my writer, the retry logic worked perfectly as expected
.
- Another weird behavior is, when I manually cause the ObjectOptimisticLockingFailureException by bumping the version column in database, with the retry definition commented in the step, the final status of the step is FAILED which is expected. But with the retry definition uncommented, the final status of the step is COMPLETE. Why is that?
This is related to the previous issue, but caused by a different one: https://github.com/spring-projects/spring-batch/issues/1189. That said, it is ok to play with the version
field during a debugging session to understand how things work, but I would not recommend changing the version
column in your code. Spring Batch relies on this column heavily in its optimistic locking strategy, and it is not expected to change values of this column in user code, otherwise unexpected behaviour might happen.
来源:https://stackoverflow.com/questions/61374981/retry-not-working-when-spring-batch-managed-transaction-rolls-back