Articles
Spring Batch Interview Questions: Chunk Transactions, Restartability, and Skip Policies
Prepare Spring Batch interview questions with a chunk failure trace, job identity, restart checkpoints, skip and retry policies, and recovery test cases.
An import writes six records successfully and fails while writing the next chunk. An operator changes a timestamp parameter and launches it again. The database now contains duplicates. Saying “Spring Batch supports restart” does not explain the failure: the operator may have created a new job instance instead of restarting the failed one.
Spring Batch interview questions become easier when you keep four boundaries visible: logical job identity, persisted reader progress, the transaction containing each chunk, and side effects outside that transaction. Recovery is correct only when those boundaries agree about what has already happened.
Here, a ten-record import gives you a concrete way to explain commits, retries, skips and restart verification.
What does a chunk commit, exactly?
In chunk-oriented processing, the step reads items, optionally processes them, passes a chunk to the writer and commits the transaction. Chunk size is not a promise that the entire job is atomic. Earlier committed chunks normally remain committed when a later chunk fails.
This article uses the maintained Spring Batch 5.2 documentation, which showed 5.2.6 when checked on September 21, 2026. The unversioned reference showed 6.0.5. The small configuration below is intentionally 5.2-style; do not mix builder signatures from different major versions.
new StepBuilder("importOrders", jobRepository)
.<InputOrder, StoredOrder>chunk(3, transactionManager)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
This is an illustrative fragment, not a complete application or an executed integration test. Its dependencies must be configured, and the writer must actually participate in the transaction selected by transactionManager.
Ask what the transaction covers. JDBC writes using the participating connection can roll back together. An HTTP request to a partner service does not become part of that local database transaction merely because it occurs inside write. That distinction determines whether rerunning work is harmless or dangerous.
Trace the failure before discussing restart
Assume ten immutable input records, numbered 1 through 10, a chunk size of three, no filtering or skipping, and a stateful reader. Assume business writes and restart metadata have consistent transactional persistence. The third chunk fails before commit; the process then ends. This is a worked thought experiment, not a measured Spring execution.
| Point in the import | Durable business rows | Durable reader progress | Meaning |
|---|---|---|---|
| Before the first chunk | None | Before record 1 | Nothing has committed |
| After chunk 1 commits | 1–3 | Through record 3 | First recovery boundary |
| After chunk 2 commits | 1–6 | Through record 6 | Second recovery boundary |
| Chunk 3 fails before commit | Still 1–6 | Still through record 6 | Work on 7–9 is not durable |
| Restarted chunk 3 commits | 1–9 | Through record 9 | Recovered work is now durable |
| Final short chunk commits | 1–10 | Through record 10 | End of input accounted for |
If the writer inserted record 7 before failing on record 8, record 7 still rolls back under these assumptions. “The last log line mentioned 8” is not a checkpoint. The next process should restore the last durable reader position and start with 7, not guess from console output.
Within a running step, rollback recovery may reuse buffered input rather than physically reread it. The rollback documentation describes that buffering and the special handling for transactional queue readers. Distinguish an in-process retry from a new process restoring saved state.
Now change one assumption: the writer calls an external service for record 7 before the database transaction fails. The database can still contain only 1–6 while the external service has already acted on 7. The original table no longer describes the entire system. Say which boundary changed before proposing a fix.
Is another launch a restart or a new job instance?
The Spring Batch domain model separates JobInstance, the logical run, from JobExecution, one attempt. The job name plus identifying job parameters determine the instance. A failed instance can have another execution using its existing restart state.
For the example, define the logical input as importOrders, business date 2026-09-20, and immutable input version orders-v4. A new attempt of that same input should preserve the identifying values. An identifying launch timestamp changes the identity and can start a fresh instance with no previous checkpoint.
Do not answer “always add a unique run ID” without explaining the consequence. That can be appropriate for an intentionally new import, but it is not a substitute for recovery. Conversely, reusing identifiers while silently replacing the file can cause a saved position to refer to different records.
Separate operational metadata from identity. An attempt's trigger reason may be non-identifying, while the input version is identifying. The exact choice follows the business definition of a logical run. Identity itself does not filter the input; the reader must use those parameters consistently.
A good interview follow-up is: “What prevents two different instances from modifying the same business records?” Different instance IDs are not a general application-level lock. You still need a deliberate ownership or database-concurrency policy.
What must the reader save for a reliable restart?
The ItemStream contract provides open, update and close. A stream can restore state from its ExecutionContext when opened and contribute current progress before commit. Saving an arbitrary counter in a singleton field does not survive process failure.
For an immutable file, a position plus the verified file identity may be sufficient. For a database reader, define stable ordering and how concurrent inserts or updates affect the resumed selection. An offset into a changing result set can refer to different data even if the stored number is correct.
Custom readers should be tested across close and reopen, not only across two calls to read. If a wrapper hides an ItemStream delegate, verify that the delegate receives the step lifecycle callbacks and its state is persisted. Naming the interface without registering the participating component is not a recovery design.
Keep saved state small, serializable and version-aware. A restart after deployment must still understand the previous state representation. If the new code cannot interpret it safely, stop for an explicit migration or recovery decision instead of treating unreadable state as “start from zero.”
How do skip, retry and filter differ?
They express different judgments about an item. Retry configuration addresses failures that may succeed on another attempt. Skip configuration permits selected failures within an explicit tolerance. Filtering intentionally omits an item by returning null from the processor.
| Situation | Candidate policy | What makes that policy defensible? |
|---|---|---|
| A temporary database deadlock | Bounded retry | The same valid operation may succeed later |
| A malformed optional catalog record | Classified skip, if permitted | The business accepts omission and can reconcile it |
| A valid record outside the import's scope | Filter | Exclusion is expected business behavior |
| Missing source file or lost database access | Fail and investigate | Continuing cannot produce the intended dataset |
| A balance mismatch in a required reconciliation | Fail or quarantine the run | A green job must not conceal incomplete accounting |
These examples are policy proposals, not universal defaults. Repeating a deterministic parse failure will not repair the record. Skipping every exception can turn an infrastructure outage into apparent success. Returning null for corrupt data can hide it among legitimate exclusions.
The configured skip limit is shared across read, process and write skips, although their counts are tracked separately. With a limit of two, two permitted skips can occur; the next skippable failure exceeds the limit. Do not present it as two skips per phase or per chunk.
Record the rejected identifier, reason and source version in an access-appropriate quarantine or audit trail. Avoid dumping sensitive row contents into general logs. A “completed with skips” result needs an operational owner and a reconciliation path, not just a larger threshold next time.
Does retry guarantee that a side effect happens once?
No. Recovery can repeat processor or writer work. The processor documentation explicitly discusses idempotence when cached items are reprocessed after rollback. Prefer transformations whose repeated execution does not mutate shared input or cause an irreversible action.
For the external action on record 7, define a stable idempotency key from the logical operation and record identity, not the attempt number. The receiving service must enforce that key consistently. A locally generated UUID on every retry creates different operations and defeats deduplication.
Another design is to write the business row and an outbox record in one local transaction, then deliver the outbox separately. This is a design option, not a Spring Batch exactly-once feature. The delivery worker can still retry, so the recipient or delivery protocol must handle repeated messages.
Check the crash window precisely: remote action accepted, response lost, local transaction rolled back. Retrying without reconciliation may duplicate the action; refusing to retry may lose necessary work if the action never happened. Explain how the chosen operation identity lets you resolve that ambiguity.
Should completed steps run again on restart?
Normally, completed steps are skipped when a restartable job resumes. The step-restart documentation describes allowStartIfComplete and startLimit. They answer different questions: whether a completed step may rerun, and how many starts are permitted.
For this import, an input-validation step might deliberately run again to confirm that the immutable file is still available. A destructive preparation step that truncates the destination should not casually rerun after six rows have already committed. Trace each step's effect before changing the flag.
A start limit is not an item retry count. Raising it does not repair a corrupt checkpoint or restore missing input. Likewise, successfully completing an instance is different from repeatedly relaunching it as if it had failed. Decide whether a requested backfill is a new logical input or recovery of an incomplete one.
How would you prove the recovery works?
Design a failure-injection integration test with the real reader, repository and transaction setup. Stop after the second commit, during the third write before commit, and after a commit before the surrounding process reports success. For each case, start a fresh process with the same identifying parameters and inspect durable results.
Assert exact business keys and values, not only row count. Ten rows can still contain one duplicate and one missing record. Verify the input version, restored progress, committed results, rejected-record audit and any external operation IDs. A successful job status is necessary evidence, not the whole acceptance test.
Add one deliberate negative case: change the identifying timestamp and show that it creates a new instance. Add another with a changed input file and ensure the recovery path rejects the mismatch. These tests make the assumptions behind restart visible to the next operator.
| Practice question | Batch-specific follow-up |
|---|---|
| Prioritize Critical Findings in a High-Load Batch Processor Review | Identify the recovery bug before tuning throughput. |
| Implement an Idempotent Versioned Database Update | Protect repeated writes without discarding newer changes. |
| Design a Write-Ahead Log Writer with Batch Writes | Separate buffered progress from durable completion. |
| Walk Through an ETL Project | Explain input identity and reconciliation after failure. |
| Design input validation and error handling | Defend the boundary between rejection and silent loss. |
Continue with the Spring Boot guide to connect transaction configuration with application wiring. A convincing recovery answer names what committed, what can repeat, and the observation that proves the final dataset is correct.