spring-batch icon indicating copy to clipboard operation
spring-batch copied to clipboard

Step lifecycle listener for when step is completed

Open cezarykluczynski opened this issue 2 years ago • 3 comments

I'm looking for a way to execute a callback when step is completed. StepExecutionListener does not work, because in afterStep, step is not acutally completed yet, because it's exit status can still be changed, and status in the DB table is not COMPLETED, but STARTED.

I'm looking for a way to do it, because after every step, I want to fire an automatic backup of a completed step. For that, it is required that all steps are completed, because if state is later recreated from this backup, Spring Batch would not process further.

I haven't found any way to do it in a clean manner. There is no listener that will execute after one step is completed, but next step is not yet started. If there is one, please point me out, and otherwise, would you consider adding a listener like that? I could probably try and make the PR if this feature is accepted.

cezarykluczynski avatar May 01 '23 22:05 cezarykluczynski

Thank you for opening this issue.

StepExecutionListener does not work, because in afterStep, step is not acutally completed yet, because it's exit status can still be changed, and status in the DB table is not COMPLETED, but STARTED.

The issue is with the current implementation of that callback listener in Spring Batch, which is incorrect. According to the contract of that method which states that that method is Called after execution of the step's processing logic (whether successful or failed), the status (both in memory and in the DB) should not be STARTED at that point, but rather a non-running status. The end time should be set at that point as well (as reported in #3846). So I believe this is a bug and not a feature that should be requested.

Once this is fixed, I think you can implement your requirement with a StepExecutionListener. Do you agree?

fmbenhassine avatar Jun 15 '23 14:06 fmbenhassine

@fmbenhassine Yes, if status was non-running in both memory and DB, that would solve my problem. However, the afterStep method returns an {@link ExitStatus} to combine with the normal value, which gives the chance to overwrite the original exit status. Therefore, if non-null status is returned, one more save in the AbstractStep around line 268 is needed (hopefully it's that simple). I'm also not sure if that would not break some assumptions other people are making about how Spring Batch works here, even if they rely on a bug.

cezarykluczynski avatar Jun 22 '23 18:06 cezarykluczynski

Forgive me if I'm wrong, but isn't the same problem present at the job level? I had the same behaviour using JobExecutionListeners.

gdupontf avatar Aug 16 '23 00:08 gdupontf

Yes, if status was non-running in both memory and DB, that would solve my problem

@cezarykluczynski the step execution status is now persisted before calling listeners, so it should be seen as a non-running status in both memory and job repository (even though I believe one should not query the job repository at that point, but only use the reference to the step execution that the listener provides).

That said, in hindsight, I don't understand why afterStep returns an ExitStatus.. The javadoc mentions to "give a listener a chance to modify the exit status from a step" but I don't see any use case for that (I might be missing something). I personally never used that "feature". Moreover, this is not consistent with JobExecutionListener#afterJob which returns void and not an ExitStatus. Why is one able to change the step's execution status in StepExecutionListener#afterStep, but is not able to change the job's execution status in JobExecutionListener#afterJob ?

Unless there is a good reason / use case for that, I believe that that method should be deprecated and replaced with one that returns void. I opened #5074 to discuss this and gather feedback, so please share your thoughts there. Many thanks upfront.

@gdupontf

Forgive me if I'm wrong, but isn't the same problem present at the job level? I had the same behaviour using JobExecutionListeners.

You are right, I fixed that for job listeners as well, 36068b5db84ff242032e9b00515454a84e0745d2.

fmbenhassine avatar Nov 03 '25 16:11 fmbenhassine