This post is part of a series delving into the details of the JSR-352 (Java Batch) specification. Each post examines a very specific part of the specification and looks at how it works and how you might use it in a real batch application.To start at the beginning, follow the link to the first post.
The next post in the series is here
.This series is also available as a podcast on iTunes, Google Play, Stitcher, or use the link to the RSS feed.
As your chunk step hums along, reading records, processing them, and writing results, bad things are going to happen. A likely bad thing is some record being read that has something wrong with it. Or some of the processing for a particular record goes badly – maybe you can’t find the account information for this account number. What to do? Well, your application is probably going to throw an exception. Then what happens? Well, if you do nothing the exception will blow back to the batch container and the job will fail. If it is just one bad record, you probably don’t want that.
You could, of course, catch the exception in your application code and handle it yourself. That’s not a bad idea. If the reader has a problem with the record it read, you could just go read another one and hope for better results. At some point you might get enough bad records that something is probably wrong beyond a few bad records and you want to just fail the job anyway. If the reader and the processor can both have problems with individual records, you’d want to coordinate counting bad records between them so you know when to give up.
You might want some code to keep track of which records are bad so somebody can go clean things up. Log a message somewhere or maybe put a message on a queue or maybe even send an email to somebody. More code to write and coordinate between the pieces.
Or you could just let the JSR-352 framework handle a lot of this for you. The first thing to do is define the exception you’re going to throw for a bad record to the JSL as a skippable exception. This will prevent the batch container from failing the job when it sees the exception. It will just call the reader and start another pass through the chunk loop as if nothing happened.
You can also define a skip limit for the step to stop the job if there are too many bad records that you want to skip. The batch container will keep track for you and automatically fail the job if you exceed the limit. The limit defines how many are ok to have, so if you set it to 3 the job will fail on the fourth skippable exception.
You can create a skip listener to get control when your reader, processor, or writer throws an exception you indicated was skippable. The listener gets passed the exception your application threw. If you put enough information inside the exception, the listener can take whatever action you decided on to get this record cleaned up.
Our sample starts with the JSL in UsingSkippableExceptions.xml. You can see the skip listener defined there, as well as the skip limit for the chunk (set to 3 so it hits). Our reader, RandomIntegerReader, generates random integers as ‘read’ values ranging from 0 through 110. The processor, RandomIntegerProcessor, checks for values greater than 100 and throws an application exception, SampleSkippableException, after putting the bad value inside the exception. The RandomIntegerWriter just logs the values that make it through. Finally, the SampleSkipProcessListener gets control for bad values and logs the value from the exception.
The sample parts are here: https://github.com/follisd/batch-samples