During this exercise, you will
- Run a Workflow Execution that completes successfully
- Make and deploy a change that does not affect compatibility
- Make and deploy a change that breaks compatibility, causing a non-deterministic error
- Develop an automated test to check compatibility with previous executions
- Use the
getVersion
API to implement versioning for the Workflow
Make your changes to the code in the practice
subdirectory (look for
TODO
comments that will guide you to where you should make changes to
the code). If you need a hint or want to verify your changes, look at
the complete version in the solution
subdirectory.
If you are executing the exercises in the provided GitPod environment, you can take advantage of certain aliases to aid in navigation and execution of the code.
Command | Action |
---|---|
ex1 |
Change to Exercise 1 Practice Directory |
ex1s |
Change to Exercise 1 Solution Directory |
ex1w |
Execute the Exercise 1 Worker. Must be within the appropriate directory for this to succeed. (either practice or solution ) |
ex1st |
Execute the Exercise 1 Starter, passing in a100 as the input. Must be within the appropriate directory for this to succeed. (either practice or solution ) |
ex1h |
Download the event history in JSON format for use in the Replayer |
- Change directories to the
exercises/version-workflow/practice
directory.- If you're in the GitPod environment you can run
ex1
- If you're in the GitPod environment you can run
- Run
mvn clean compile exec:java -Dexec.mainClass="getversion.LoanProcessingWorker"
in a terminal to start a Worker- If you're in the GitPod environment, you can run
ex1w
- If you're in the GitPod environment, you can run
- Run
mvn clean compile exec:java -Dexec.mainClass="getversion.Starter" -Dexec.args="a100"
in another terminal. This will start a Workflow that processes the loan for customer IDa100
.- If you're in the GitPod environment, you can run
ex1st
- If you're in the GitPod environment, you can run
- Let this Workflow run to completion. This customer has a loan with 10 payments, and since the Workflow in this exercise uses a Timer to add a three-second delay between each payment, it should complete within 30 seconds.
- You will now download the history of this execution in JSON
format so that you can replay it in an automated test that
you will develop later in this exercise. Use the
temporal
cli to download the event history:temporal workflow show \ --workflow-id loan-processing-workflow-customer-a100 \ --fields long \ --output json > history_for_original_execution.json
- You an also use the
ex1h
command within the GitPod environment to save yourself some typing. - NOTE You can also download the event history from the Web UI, however, this
is currently not supported in the GitPod environment. To download the
history navigate to the Event History section
of the detail page for this execution, and then click the
Download button just above the table showing the Event History.
In the Download JSON dialog, disable the
Decode Event History toggle, and then click Download. Save
the file as
history_for_original_execution.json
in yourpractice
directory.
- You an also use the
- In the next section, you will make and deploy an incompatible
change, causing a non-deterministic error for an open execution.
To allow time for you to do these things, edit the
LoanProcessingWorkflowImpl.java
file and change the duration in theWorkflow.sleep
call from 3 seconds to 90 seconds. - Save your change to the
LoanProcessingWorkflowImpl.java
file and exit the editor - Compile the code with
mvn clean compile
- Restart the Worker by pressing Ctrl-C in the terminal window
from step 1 and running the
mvn clean compile exec:java -Dexec.mainClass="getversion.LoanProcessingWorker"
command again- If you're in the GitPod environment, you can run
ex1w
- If you're in the GitPod environment, you can run
- Run the Workflow again:
mvn clean compile exec:java -Dexec.mainClass="getversion.Starter" -Dexec.args="a100"
- If you're in the GitPod environment, you can run
ex1st
- If you're in the GitPod environment, you can run
- Use the Web UI to verify that the Workflow Execution from the previous step is running before proceeding with the next part of this exercise.
- This Workflow uses the
sendThankYouToCustomer
Activity to send a thank you message to the customer before charging them with the first loan payment, but this was a mistake. This Activity should run after the last payment. To fix this, edit theLoanProcessingWorkflowImpl.java
file and move the line of code used start to Activity executionString confirmation = activities.sendThankYouToCustomer(info);
from just before the loop to just after the loop. - Save your change and exit the editor.
- Stop the Worker by pressing Ctrl-C in the terminal window where you stasrted it.
- Compile the code with
mvn clean compile
- Restart the Worker by then running the
mvn clean compile exec:java -Dexec.mainClass="getversion.LoanProcessingWorker"
command again.- If you're in the GitPod environment, you can run
ex1w
- If you're in the GitPod environment, you can run
- The change you just made to the Workflow logic takes effect immediately, although the Worker immediately begins using the updated code you deployed, it may take up to 90 seconds before that is evident for this Workflow Execution, due to the duration of the Timer.
- Refresh the detail page for this execution in the Web UI. Continue to refresh the page until the non-deterministic error is visible.
The non-deterministic error occurs because of your change to the Workflow logic. By moving the Activity from before the loop to after it, the sequence of Commands generated during execution is different with the new code than it was prior to the change.
Recall that you had an open Workflow Execution when you restarted the Worker during the deployment. The Worker used History Replay to recover the state of the open execution prior to the restart. Since the Commands generated when replaying it with the new code did not correspond to the Events that were generated when the Worker ran the original code before the restart, it is unable to recover the state and responds by throwing the non-deterministic error you see.
- Edit the
LoanProcessingWorkflowTest.java
file and implement the following in theTestReplayWorkflowHistoryFromFile
function:- Create a File object for the Event History you downloaded
- Use
assertDoesNotThrow
to verify that replaying the history does not return an error- Create the Workflow Replayer and call it from within the assert
- Replay the Event History in the JSON file you downloaded
- Save your changes
- Run
mvn clean compile test
. You should find that this fails, which confirms altering the execution order of thesendThankYouToCustomer
Activity) breaks compatibility. In the final part of this exercise, you will use thegetVersion
API to implement versioning for your change, thereby making it compatible with Workflow Executions started before or after the change.
Just above the loop, where the Activity call was prior to the change, add the following lines:
String versionKey = "MovedThankYouAfterLoop";
int version = Workflow.getVersion(versionKey, Workflow.DEFAULT_VERSION, 1);
if (version != Workflow.DEFAULT_VERSION) {
Workflow.upsertTypedSearchAttributes(TEMPORAL_CHANGE_VERSION
.valueSet(Arrays.asList((versionKey + "-" + version))));
}
This establishes a logical branch for code execution, identified
by the user-defined Change ID MovedThankYouAfterLoop
. Since there
was no versioning in place prior to this change, the minimum supported
version is workflow.DEFAULT_VERSION
and the maximum supported version
is 1
.
- Add a conditional statement just after this new line: If the value
of
version
is equal to@Workflow.DEFAULT_VERSION
, meaning that it represents a Workflow Execution started when the Activity was called before the loop, then invoke the Activity call there. In other words, copy the same lines you moved after the loop to inside the braces for this conditional statement, so that this Activity will be called if the condition evaluates totrue
. - Wrap the code you previously moved after the loop in a
conditional statement that tests if
version
is equal to1
. This will handle the Activity for Workflow Executions started after the change. - Change the duration of the
Workflow.sleep
statement at the bottom of the loop back to 3 seconds. This is unrelated to versioning and changing the duration of a timer does not require versioning, but will help you see the results more quickly. - Run
mvn clean compile test
again. You should find it succeeds this time, since you've used thegetVersion
API to restore compatibility with the previous execution. - Restart the Worker by pressing Ctrl-C in the terminal
window where you started it and then running the
mvn clean compile exec:java -Dexec.mainClass="getversion.LoanProcessingWorker"
command again.- If you're in the GitPod environment, you can run
ex1w
- If you're in the GitPod environment, you can run
- Return to the detail page for this Workflow Execution
- Click the downward-facing arrow to the right of the
Request Cancellation menu near the upper-right portion of
the page and select the Reset option.
- Select the last WorkflowTaskCompleted event to reset to
- Enter "Using versioning to fix a bad deployment" as the reason
- Click the Confirm button
- The Workflow will now be terminated a new Workflow started, resuming from
the specified Workflow Task. Return to the dashboard and view progress of
that Workflow Execution.
- The WebUI may still show a warning about Reset Workflow at the top of the page. Monitor the Event History and the log output from the Worker to confirm that progress has resumed.
- Enable the auto-refresh feature using the toggle button near the top of the page. You should find that the Workflow Execution completes successfully within the next 30 seconds.