Versioning - Java SDK
The Temporal Platform requires that Workflow code is deterministic. Because of that requirement, the Temporal Java SDK offers two dedicated versioning features:
How to patch Workflows in Java
Use the Workflow.getVersion
function to return a version of the code that should be executed and then use the returned value to pick a correct branch.
Let's look at an example.
public void processFile(Arguments args) {
String localName = null;
String processedName = null;
try {
localName = activities.download(args.getSourceBucketName(), args.getSourceFilename());
processedName = activities.processFile(localName);
activities.upload(args.getTargetBucketName(), args.getTargetFilename(), processedName);
} finally {
if (localName != null) { // File was downloaded.
activities.deleteLocalFile(localName);
}
if (processedName != null) { // File was processed.
activities.deleteLocalFile(processedName);
}
}
}
Now we decide to calculate the processed file checksum and pass it to upload. The correct way to implement this change is:
public void processFile(Arguments args) {
String localName = null;
String processedName = null;
try {
localName = activities.download(args.getSourceBucketName(), args.getSourceFilename());
processedName = activities.processFile(localName);
int version = Workflow.getVersion("checksumAdded", Workflow.DEFAULT_VERSION, 1);
if (version == Workflow.DEFAULT_VERSION) {
activities.upload(args.getTargetBucketName(), args.getTargetFilename(), processedName);
} else {
long checksum = activities.calculateChecksum(processedName);
activities.uploadWithChecksum(
args.getTargetBucketName(), args.getTargetFilename(), processedName, checksum);
}
} finally {
if (localName != null) { // File was downloaded.
activities.deleteLocalFile(localName);
}
if (processedName != null) { // File was processed.
activities.deleteLocalFile(processedName);
}
}
}
Later, when all Workflows that use the old version are completed, the old branch can be removed.
public void processFile(Arguments args) {
String localName = null;
String processedName = null;
try {
localName = activities.download(args.getSourceBucketName(), args.getSourceFilename());
processedName = activities.processFile(localName);
// getVersion call is left here to ensure that any attempt to replay history
// for a different version fails. It can be removed later when there is no possibility
// of this happening.
Workflow.getVersion("checksumAdded", 1, 1);
long checksum = activities.calculateChecksum(processedName);
activities.uploadWithChecksum(
args.getTargetBucketName(), args.getTargetFilename(), processedName, checksum);
} finally {
if (localName != null) { // File was downloaded.
activities.deleteLocalFile(localName);
}
if (processedName != null) { // File was processed.
activities.deleteLocalFile(processedName);
}
}
}
The Id that is passed to the getVersion
call identifies the change. Each change is expected to have its own Id. But if
a change spawns multiple places in the Workflow code and the new code should be either executed in all of them or
in none of them, then they have to share the Id.
Adding Support for Versioned Workflow Visibility in the Event History
In other Temporal SDKs, when you invoke the Patching API, the SDK records an
UpsertWorkflowSearchAttribute
Event in the history. This adds support
for a custom query parameter in the web UI named TemporalChangeVersion
that
allows you to filter Workflows based on their version. Unfortunately, the Java
SDK doesn't currently support the automatic adding of this attribute, so you'll
have to do it manually instead.
Within your Workflow Implementation code you'll need to perform the following steps: