Add spring-batch: jobs, steps, chunk processing and restartability on Boot 4.1
Companion code for "Spring Batch on Boot 4.1: Jobs, Steps, Chunk Processing and Restartability". A productImportJob configured three ways by profile against a poisoned CSV row, run as real java -jar processes (not just JUnit) so the restart story is genuine: a chunk fails and rolls back, the process exits, a brand-new JVM against the same file-based H2 database resumes at the exact next unread row (READ_COUNT 20, not 60) and completes. Findings the build pins: - StepBuilder.chunk(int, PlatformTransactionManager) still compiles in Batch 6.0.5 but returns the legacy SimpleStepBuilder; chunk(int) returns the new ChunkOrientedStepBuilder, and only the latter is used here. - Two different ExecutionContext classes now exist in two different packages (infrastructure.item vs core.repository.persistence) with different shapes. - spring-boot-starter-batch alone gives a resourceless JobRepository that forgets every JobInstance the moment the JVM exits; spring-boot-starter- batch-jdbc is what makes the restart demo possible at all, demonstrated by excluding BatchJdbcAutoConfiguration and watching a "restart" collide with the previous run's own data instead of resuming it. - A migration-guide summary claiming CommandLineJobRunner was removed in 6.0 is wrong -- javap against the real jar shows @Deprecated(forRemoval=true), not removed. - RepeatStatus moved from core.repeat to infrastructure.repeat, caught by the compiler rather than by reading docs. 11 documentation chapters, 10 captured transcripts (unit tests, javap output, and real two-JVM scenario runs), all regenerated by scripts/run-all.sh. Fixed after push: three dead docs.spring.io links in the doc chapters (readersAndWriters/* and chunk-oriented-processing/*.html paths moved when Spring Batch 6 reorganized its reference docs; corrected to the current readers-and-writers/*, processor.html and chunk-oriented-processing.html paths, verified 200 via curl before committing). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019DXsJ1zpikbA1MQJN6RqFA
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# 5. Launching a job, and why restart is not a separate API
|
||||
|
||||
[← Previous](04-item-processor-as-filter.md) | [README](../README.md) | [Next: The JDBC writer and Java records →](06-jdbc-writer-and-records.md)
|
||||
|
||||
[`ImportRunner`](../src/main/java/com/ankurm/batch/runner/ImportRunner.java) launches the job
|
||||
with:
|
||||
|
||||
```java
|
||||
var params = new JobParametersBuilder()
|
||||
.addString("batch.run", "demo") // identifying
|
||||
.toJobParameters();
|
||||
try {
|
||||
var execution = jobOperator.start(job, params);
|
||||
} catch (JobInstanceAlreadyCompleteException e) {
|
||||
// already succeeded; nothing to do
|
||||
}
|
||||
```
|
||||
|
||||
`JobParametersBuilder` and `addString(...)` look exactly like Spring Batch 4 and 5. What changed
|
||||
underneath is the type it builds: `JobParameters` is now an immutable record holding a
|
||||
`Set<JobParameter<?>>`, and each `JobParameter<T>` is itself a record carrying its own name,
|
||||
value, type, and an `identifying` flag (default `true` for the `addX` methods used here). None of
|
||||
that shows up in this code — it matters if you ever construct a `JobParameters` by hand
|
||||
instead of through the builder, or serialize one.
|
||||
|
||||
## "Identifying" is the whole restart mechanism
|
||||
|
||||
A **JobInstance** is identified by a job name plus the set of parameters marked `identifying`.
|
||||
Calling `jobOperator.start(job, params)` with parameters that match an existing JobInstance does
|
||||
not create a second, independent run:
|
||||
|
||||
- If that instance's last execution is not `COMPLETED` (it `FAILED`, or never finished), Spring
|
||||
Batch creates a new `JobExecution` **against the same instance** and each step resumes from
|
||||
its own last-committed position. This is a restart, and it happens through the exact same
|
||||
`start()` call as a first attempt — see [chapter 7](07-restartability.md) for what
|
||||
"resumes from" means concretely.
|
||||
- If that instance's last execution `COMPLETED`, `start()` throws
|
||||
`JobInstanceAlreadyCompleteException` (unless the step allows re-running —
|
||||
`allowStartIfComplete`, used on `reportStep`; see [chapter 8](08-skip-vs-restart.md)).
|
||||
|
||||
There is a separate `JobOperator.restart(long executionId)` method for restarting by execution
|
||||
ID explicitly, useful for an operational tool that lists failed executions and lets someone pick
|
||||
one. This module does not need it: every run uses the same identifying parameter
|
||||
(`batch.run=demo`), so plain `start()` already does the right thing whether this is attempt one
|
||||
or attempt two. If you want a fresh JobInstance on every run instead — the common pattern
|
||||
for "run this daily" jobs — add a parameter that changes each time, typically a timestamp
|
||||
or an incrementer, and mark it identifying (the default).
|
||||
|
||||
## `spring.batch.job.enabled`
|
||||
|
||||
Spring Boot auto-configures a `JobLauncherApplicationRunner` that launches every `Job` bean it
|
||||
finds using empty parameters, on every application startup. This module turns that off
|
||||
(`spring.batch.job.enabled: false` in [`application.yml`](../src/main/resources/application.yml))
|
||||
because `ImportRunner` needs to control the parameters (the identifying `batch.run` value) and
|
||||
which profile's `Job` bean is active. Leaving both runners on would launch the job twice per
|
||||
startup with two different parameter sets. If you only ever need "run the one job on startup
|
||||
with no arguments," the auto-configured runner is simpler and this whole class is unnecessary.
|
||||
|
||||
## Going deeper
|
||||
|
||||
- `JobParameters` and identifying parameters: [Spring Batch reference — running a job](https://docs.spring.io/spring-batch/reference/job/running.html) (`rel="nofollow"`).
|
||||
- `spring.batch.job.name` for selecting which job the auto-configured runner launches, when you
|
||||
have more than one `Job` bean and want to keep using it.
|
||||
|
||||
[Next: The JDBC writer and Java records →](06-jdbc-writer-and-records.md)
|
||||
Reference in New Issue
Block a user