Josh
Josh

Reputation: 371

Step Listener to add failed steps to execution context

I was wondering if there is a way to use a the afterStep and make a step exceution listener to check for any failed steps in a job, and add that step name and exit status to the execution context.

Although a step in my job has failed, we return RepeatStatus.FINISHED. I create an email report and I want to include the failed step name and status. Here's my email tasklet

public class SendEmailTasklet implements Tasklet {

    final static Logger LOGGER = LoggerFactory.getLogger(SendEmailTasklet.class);

    @Autowired
    public JavaMailSender emailSender;

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

        JobParameters jobParameters = chunkContext.getStepContext().getStepExecution().getJobParameters();
        ExecutionContext ec = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext();

        //obtain email address and program name from the execution context
        String programName = ec.getString(AbstractSetupTasklet.BATCH_PROGRAM_NAME);
        String toEmail = jobParameters.getString("TOEMAIL");

        if(StringUtils.isEmpty(toEmail)) {

            LOGGER.info("No email address associated with the user. Job status is " + programStatus);

            return RepeatStatus.FINISHED;
        }
        else {

            //construct the message
            SimpleMailMessage message = new SimpleMailMessage();
            message.setTo(toEmail);
            message.setSubject("Batch Reporting");
            message.setText("The batch program " + programName + " has exited with a status of " + programStatus);
            emailSender.send(message);

            LOGGER.info("Email succesfully sent to user at " + toEmail);

            return RepeatStatus.FINISHED;
        }
    }


}

As seen in the code above, I want to return the programStatus or something that says 'the job failed on X step with a status of X'

EDIT:

For anyone wondering, I'll post my completed code below. I made a new method to construct an email message to cut down on repeat code as well

public class SendEmailTasklet implements Tasklet {

    final static Logger LOGGER = LoggerFactory.getLogger(SendEmailTasklet.class);

    @Autowired
    public JavaMailSender emailSender;

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

        //Get the job info
        JobParameters jobParameters = chunkContext.getStepContext().getStepExecution().getJobParameters();
        ExecutionContext ec = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext();

        //Get the step info
        JobExecution jobExecutions = chunkContext.getStepContext().getStepExecution().getJobExecution();
        Collection<StepExecution> stepExecution = jobExecutions.getStepExecutions();

        //Get the email address and program name
        String programName = ec.getString(AbstractSetupTasklet.BATCH_PROGRAM_NAME);
        String toEmail = jobParameters.getString("TOEMAIL");


        //If no email address exists, do not send the email.
        if(StringUtils.isEmpty(toEmail)) {

            LOGGER.info("No email address associated with the user.");
            return RepeatStatus.FINISHED;

        }
        else {

            //Check for the first failed step
            for (StepExecution step : stepExecution) {
                if(step.getExitStatus().equals(ExitStatus.FAILED)) {
                    String failedStep = step.getStepName();
                    sendBatchReportEmail(toEmail, programName, failedStep);
                    LOGGER.info(programName + " has failed on the step " + failedStep);
                    break;
                }
            }
            sendBatchReportEmail(toEmail, programName, null);
            LOGGER.info("No email address associated with the user.");
            return RepeatStatus.FINISHED;
        }

    }

    public void sendBatchReportEmail(String toEmail, String programName, String stepName) {
        if(Utils.isEmpty(stepName)) {
            //construct the message
            SimpleMailMessage message = new SimpleMailMessage();
            message.setTo(toEmail);
            message.setSubject("Batch Reporting");
            message.setText("The batch program " + programName + " has completed.");
            emailSender.send(message);
            LOGGER.info("Email succesfully sent to user at " + toEmail);            
        }
        else {
          //construct the message
            SimpleMailMessage message = new SimpleMailMessage();
            message.setTo(toEmail);
            message.setSubject("Batch Reporting");
            message.setText("The batch program " + programName + " has failed on step: " + stepName);
            emailSender.send(message);
            LOGGER.info("Email succesfully sent to user at " + toEmail + "and has failed on the step: " + stepName);
        }

    }

}

Upvotes: 0

Views: 702

Answers (1)

Mahmoud Ben Hassine
Mahmoud Ben Hassine

Reputation: 31590

You can get access to the job execution from the chunk context with chunkContext.getStepContext().getStepExecution().getJobExecution().

Once you have the job execution, you can get all step executions with jobExecution.getStepExecutions() and iterate through them to check the last failed step.

The last failed StepExecution gives you the step name, exit code and description which you need to create your message then add it to the job execution context.

Hope this helps.

Upvotes: 1

Related Questions