Files
spring-boot-demo/spring-batch/docs/11-production-checklist.md
T
Claude b81af72bc3 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
2026-09-13 06:37:46 +00:00

3.4 KiB

11. Production checklist

← Previous | README

A short list, aimed at the gap between "this demo works" and "this is safe to point at a real feed." Each item links back to the chapter that explains the why.

  • Confirm the job repository is actually persistent — query for BATCH_JOB_INSTANCE after startup, don't assume from the dependency list. Chapter 10.
  • Pick chunk size from measurement, not habit. Smaller costs more round trips; larger costs more rework per failure. Chapter 3.
  • Decide skip vs. fail-and-restart per failure type, not per job. A step can have a skipLimit for genuinely expected bad rows and still fail hard past that limit — the two are not mutually exclusive. Chapter 8.
  • Use chunk(int).transactionManager(tx), not chunk(int, tx), unless you specifically need the legacy SimpleStepBuilder for something the new model does not yet cover. Chapter 2.
  • Do not use beanMapped() against a Java record without checking your exact Spring Framework version's record support; prefer itemPreparedStatementSetter when in doubt. Chapter 6.
  • Give every step you want to always re-run on restart allowStartIfComplete(true) explicitly — a reporting or notification step that silently gets skipped after a restart is a surprising, hard-to-notice gap. Chapter 8.
  • A custom ItemReader that does not implement ItemStream restarts from scratch every time, which is fine for an idempotent reader and a bug for anything else — check this deliberately rather than by finding out during an incident. Chapter 7.
  • spring.batch.job.enabled=false if you launch jobs yourself through JobOperator, so the auto-configured runner does not also try. Chapter 5.
  • Delete or secure any diagnostic endpoint you add while building this out. This module has none, but the pattern (an endpoint dumping live JobExplorer state) is common enough to call out: it is invaluable while developing and a liability left in production.

Should you even build a custom batch job for this?

Sometimes the honest answer is no. If the volume is small enough to fit in a single request-response cycle and does not need to survive a crash mid-way, a scheduled @Component method with its own try/catch is less machinery than a full Job/Step/JobRepository setup, and easier for the next person to read. Spring Batch earns its complexity when you actually need the things this article demonstrates — durable progress tracking, transactional chunking, a real restart story — not by default just because the word "batch" is in the requirements.

Further reading