While executing a composed task, a user may encounter an error due to a uniq run.id
Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={run.id=###}. If you want to run this job again, change the parameters.
Spring Cloud Data Flow's Composed Task Runner (CTR) is a Spring Batch application. Spring Batch requires that every execution of the same job is uniquely identified by its job parameters — this is how it tracks execution history, prevents duplicate runs, and enables restartability.
By default, the CTR uses a parameter called run.id (a sequential Long) to satisfy this uniqueness requirement. Before each launch, the CTR reads the last run.id value from the database and increments it by 1. This value is passed to the SCDF server as part of the task launch request, and the SCDF server records it in the Batch metadata tables.
The sequential incrementer is stateful: it depends entirely on reading the correct last value from the database. Any disruption that affects the consistency of that state — such as a database restart, point-in-time restore, failover to a replica, or partial rollback — can cause the incrementer to return a value that has already been used for a successfully completed run.
When that happens, Spring Batch throws:
JobInstanceAlreadyCompleteException: A job instance already exists and is completefor parameters={run.id=<N>}.This error repeats on every subsequent launch because the underlying database state does not change. The CTR cannot proceed regardless of how many times it is retried.
Add the following to the composed task launch properties:
app.composed-task-runner.uuid-instance-enabled=trueThis can be set as a default deployment property on the composed task definition so that it applies to all future launches without requiring per-request configuration.
Property: app.composed-task-runner.uuid-instance-enabled=true
When set to true, the CTR replaces the sequential run.id counter with a randomly generated UUID (e.g. ######-#####-#####-######). This UUID is generated fresh at startup, without reading anything from the database. It is passed to the SCDF server as the job-identifying parameter ctr.id instead of run.id.
This makes uniqueness stateless: there is no dependency on the current contents of any database table, and no value that a DB restart or restore can invalidate.
The SCDF server is responsible for launching the CTR as a task. The job parameters — including the uniqueness parameter — are passed from the server to the CTR at launch time and recorded in the Batch metadata tables shared between the server and the CTR. The server itself does not generate run.id or ctr.id; that is entirely the CTR's responsibility via its configured incrementer.
When uuid-instance-enabled=true, the server receives and records ctr.id instead of run.id. This is fully supported and transparent to the server — no server-side configuration change is required.
Yes. uuid-instance-enabled=true is the recommended configuration for production use. Specifically:
With uuid-instance-enabled=true in effect, log output and error messages will reference both run.id and ctr.id. This is expected and not a cause for concern.
For example, a successful launch will show something like:
Job: [FlowJob: [name=my-composed-task]] launched with the following parameters:[{run.id=###, ctr.id=####-####-####-####-##########}]In practical terms: when correlating log output or database records across launches, use ctr.id as the stable identifier for a given composed task execution. run.id will continue to increment but is effectively inert.