Skip to content

Commit 8d03c15

Browse files
authored
IWF-101: Use different structures for WorkflowStateOptions (#283)
1 parent 055f283 commit 8d03c15

20 files changed

+483
-197
lines changed

src/main/java/io/iworkflow/core/Client.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import io.iworkflow.core.exceptions.NoRunningWorkflowException;
55
import io.iworkflow.core.exceptions.WorkflowAlreadyStartedException;
66
import io.iworkflow.core.exceptions.WorkflowNotExistsException;
7-
import io.iworkflow.core.mapper.StateMovementMapper;
87
import io.iworkflow.core.persistence.PersistenceOptions;
98
import io.iworkflow.gen.models.ErrorSubStatus;
109
import io.iworkflow.gen.models.KeyValue;
@@ -32,6 +31,8 @@
3231
import java.util.stream.Collectors;
3332

3433
import static io.iworkflow.core.WorkflowState.shouldSkipWaitUntil;
34+
import static io.iworkflow.core.mapper.StateMovementMapper.autoFillFailureProceedingStateOptions;
35+
import static io.iworkflow.core.mapper.StateMovementMapper.toIdlWorkflowStateOptionsWithValidation;
3536

3637
public class Client {
3738
private final Registry registry;
@@ -172,7 +173,7 @@ public String startWorkflow(
172173
throw new WorkflowDefinitionException(String.format("input cannot be assigned to the starting state, input type: %s, starting state input type: %s", input.getClass(), registeredInputType));
173174
}
174175

175-
WorkflowStateOptions stateOptions = StateMovementMapper.validateAndGetStateOptionsCopy(stateDef);
176+
WorkflowStateOptions stateOptions = toIdlWorkflowStateOptionsWithValidation(stateDef);
176177
if (shouldSkipWaitUntil(stateDef.getWorkflowState())) {
177178
if (stateOptions == null) {
178179
stateOptions = new WorkflowStateOptions().skipWaitUntil(true);
@@ -181,7 +182,7 @@ public String startWorkflow(
181182
}
182183
}
183184

184-
StateMovementMapper.autoFillFailureProceedingStateOptions(stateOptions, wfType, registry);
185+
autoFillFailureProceedingStateOptions(stateOptions, wfType, registry);
185186

186187
if (stateOptions != null) {
187188
unregisterWorkflowOptions.startStateOptions(stateOptions);

src/main/java/io/iworkflow/core/StateDecision.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.iworkflow.core;
22

33
import io.iworkflow.gen.models.WorkflowConditionalCloseType;
4-
import io.iworkflow.gen.models.WorkflowStateOptions;
54
import org.immutables.value.Value;
65

76
import java.util.ArrayList;

src/main/java/io/iworkflow/core/StateMovement.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.iworkflow.core;
22

3-
import io.iworkflow.gen.models.WorkflowStateOptions;
43
import org.immutables.value.Value;
54

65
import java.util.Optional;

src/main/java/io/iworkflow/core/WorkflowState.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import io.iworkflow.core.command.CommandResults;
55
import io.iworkflow.core.communication.Communication;
66
import io.iworkflow.core.persistence.Persistence;
7-
import io.iworkflow.gen.models.WorkflowStateOptions;
87

98
import java.lang.reflect.Method;
109

@@ -92,7 +91,6 @@ default String getStateId() {
9291
* - MaxInternalSeconds:100
9392
* - MaximumAttempts: 0
9493
* - BackoffCoefficient: 2
95-
* See {@link WorkflowStateOptionsExtension} for some helpers to build the options.
9694
* @return the optional options
9795
*/
9896
default WorkflowStateOptions getStateOptions() {

src/main/java/io/iworkflow/core/WorkflowStateOptions.java

Lines changed: 351 additions & 0 deletions
Large diffs are not rendered by default.

src/main/java/io/iworkflow/core/WorkflowStateOptionsExtension.java

Lines changed: 0 additions & 121 deletions
This file was deleted.

src/main/java/io/iworkflow/core/mapper/StateMovementMapper.java

Lines changed: 87 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
import static io.iworkflow.core.StateMovement.RESERVED_STATE_ID_PREFIX;
1515
import static io.iworkflow.core.WorkflowState.shouldSkipWaitUntil;
16-
import static io.iworkflow.core.WorkflowStateOptionsExtension.deepCopyStateOptions;
1716

1817
public class StateMovementMapper {
1918

@@ -31,10 +30,10 @@ public static StateMovement toGenerated(final io.iworkflow.core.StateMovement st
3130
// Try to get the overrode stateOptions, if it's null, get the stateOptions from stateDef
3231
WorkflowStateOptions stateOptions;
3332
if (stateMovement.getStateOptionsOverride().isPresent()) {
34-
// Always deep copy the state options so we don't modify the original
35-
stateOptions = deepCopyStateOptions(stateMovement.getStateOptionsOverride().get());
33+
stateOptions =
34+
toIdlWorkflowStateOptionsWithValidation(stateMovement.getStateOptionsOverride().get(), stateMovement.getStateId());
3635
} else {
37-
stateOptions = StateMovementMapper.validateAndGetStateOptionsCopy(stateDef);
36+
stateOptions = toIdlWorkflowStateOptionsWithValidation(stateDef);
3837
}
3938

4039
if (shouldSkipWaitUntil(stateDef.getWorkflowState())) {
@@ -66,7 +65,7 @@ public static void autoFillFailureProceedingStateOptions(WorkflowStateOptions st
6665
// fill the state options for the proceeding state
6766
String proceedStateId = stateOptions.getExecuteApiFailureProceedStateId();
6867
final StateDef proceedStatDef = registry.getWorkflowState(workflowType, proceedStateId);
69-
WorkflowStateOptions proceedStateOptions = StateMovementMapper.validateAndGetStateOptionsCopy(proceedStatDef);
68+
WorkflowStateOptions proceedStateOptions = toIdlWorkflowStateOptionsWithValidation(proceedStatDef);
7069
if (proceedStateOptions != null &&
7170
proceedStateOptions.getExecuteApiFailurePolicy() == ExecuteApiFailurePolicy.PROCEED_TO_CONFIGURED_STATE) {
7271
throw new WorkflowDefinitionException("nested failure handling is not supported. You cannot set a failure proceeding state on top of another failure proceeding state.");
@@ -84,35 +83,100 @@ public static void autoFillFailureProceedingStateOptions(WorkflowStateOptions st
8483
}
8584
}
8685

87-
public static WorkflowStateOptions validateAndGetStateOptionsCopy(final StateDef stateDef){
88-
final WorkflowState state = stateDef.getWorkflowState();
89-
// Always deep copy the state options so we don't modify the original
90-
WorkflowStateOptions stateOptions = deepCopyStateOptions(state.getStateOptions());
91-
if (stateOptions == null){
92-
return null;
93-
}
94-
if(stateOptions.getExecuteApiFailurePolicy() == ExecuteApiFailurePolicy.PROCEED_TO_CONFIGURED_STATE){
86+
/**
87+
* Validates if the required fields are present when the {@link WorkflowStateOptions} is configured to proceed on Execute
88+
* API Failure.
89+
* @param stateOptions the state options to validate.
90+
* @param stateId the unique ID of the state
91+
*/
92+
private static void validateExecuteApiFailurePolicy(WorkflowStateOptions stateOptions, String stateId) {
93+
// Validate required fields if Execute failure policy is configured to proceed
94+
if (stateOptions.getExecuteApiFailurePolicy() == ExecuteApiFailurePolicy.PROCEED_TO_CONFIGURED_STATE) {
9595
// retry policy must be set
96-
if(stateOptions.getExecuteApiRetryPolicy() == null){
97-
throw new WorkflowDefinitionException("RetryPolicy must be set for the execute "+state.getStateId());
96+
if (stateOptions.getExecuteApiRetryPolicy() == null) {
97+
throw new WorkflowDefinitionException("RetryPolicy must be set for the execute " + stateId);
9898
}
9999
final RetryPolicy policy = stateOptions.getExecuteApiRetryPolicy();
100100
// either maximumAttempts or maximumAttemptsDurationSeconds must be set and greater than zero
101-
if(policy.getMaximumAttempts() == null && policy.getMaximumAttemptsDurationSeconds() == null){
102-
throw new WorkflowDefinitionException("Either maximumAttempts or maximumAttemptsDurationSeconds must be set for the execute "+state.getStateId());
101+
if (policy.getMaximumAttempts() == null && policy.getMaximumAttemptsDurationSeconds() == null) {
102+
throw new WorkflowDefinitionException(
103+
"Either maximumAttempts or maximumAttemptsDurationSeconds must be set for the execute " + stateId);
103104
}
104105
}
105-
if(stateOptions.getWaitUntilApiFailurePolicy() == WaitUntilApiFailurePolicy.FAIL_WORKFLOW_ON_FAILURE){
106+
}
107+
108+
/**
109+
* Validates if the required fields are present when the {@link WorkflowStateOptions} is configured to proceed on WaitUntil
110+
* API Failure.
111+
* @param stateOptions the state options to validate.
112+
* @param stateId the unique ID of the state
113+
*/
114+
private static void validateWaitUntilApiFailurePolicy(WorkflowStateOptions stateOptions, String stateId) {
115+
// Validate required fields if Wait Until failure policy is configured to proceed
116+
if (stateOptions.getWaitUntilApiFailurePolicy() == WaitUntilApiFailurePolicy.PROCEED_ON_FAILURE) {
106117
// retry policy must be set
107-
if(stateOptions.getWaitUntilApiRetryPolicy() == null){
108-
throw new WorkflowDefinitionException("RetryPolicy must be set for the waitUntil "+state.getStateId());
118+
if (stateOptions.getWaitUntilApiRetryPolicy() == null) {
119+
throw new WorkflowDefinitionException("RetryPolicy must be set for the waitUntil " + stateId);
109120
}
110121
final RetryPolicy policy = stateOptions.getWaitUntilApiRetryPolicy();
111122
// either maximumAttempts or maximumAttemptsDurationSeconds must be set and greater than zero
112-
if(policy.getMaximumAttempts() == null && policy.getMaximumAttemptsDurationSeconds() == null){
113-
throw new WorkflowDefinitionException("Either maximumAttempts or maximumAttemptsDurationSeconds must be set for the waitUntil "+state.getStateId());
123+
if (policy.getMaximumAttempts() == null && policy.getMaximumAttemptsDurationSeconds() == null) {
124+
throw new WorkflowDefinitionException(
125+
"Either maximumAttempts or maximumAttemptsDurationSeconds must be set for the waitUntil " + stateId);
114126
}
115127
}
116-
return stateOptions;
128+
}
129+
130+
public static WorkflowStateOptions toIdlWorkflowStateOptionsWithValidation(final StateDef stateDef) {
131+
final WorkflowState state = stateDef.getWorkflowState();
132+
if (state.getStateOptions() == null) {
133+
return null;
134+
}
135+
136+
return toIdlWorkflowStateOptionsWithValidation(state.getStateOptions(), state.getStateId());
137+
}
138+
139+
public static WorkflowStateOptions toIdlWorkflowStateOptionsWithValidation(
140+
io.iworkflow.core.WorkflowStateOptions stateOptions,
141+
String stateId) {
142+
if (stateOptions == null) {
143+
return null;
144+
}
145+
146+
// Guarantee workflow state options copy is not holding references to the original by cloning object
147+
stateOptions = stateOptions.clone();
148+
149+
final WorkflowStateOptions idlWorkflowStateOptions = new WorkflowStateOptions();
150+
151+
idlWorkflowStateOptions.setSearchAttributesLoadingPolicy(stateOptions.getSearchAttributesLoadingPolicy());
152+
idlWorkflowStateOptions.setWaitUntilApiSearchAttributesLoadingPolicy(stateOptions.getWaitUntilApiSearchAttributesLoadingPolicy());
153+
idlWorkflowStateOptions.setExecuteApiSearchAttributesLoadingPolicy(stateOptions.getExecuteApiSearchAttributesLoadingPolicy());
154+
idlWorkflowStateOptions.setDataAttributesLoadingPolicy(stateOptions.getDataAttributesLoadingPolicy());
155+
idlWorkflowStateOptions.setWaitUntilApiDataAttributesLoadingPolicy(stateOptions.getWaitUntilApiDataAttributesLoadingPolicy());
156+
idlWorkflowStateOptions.setExecuteApiDataAttributesLoadingPolicy(stateOptions.getExecuteApiDataAttributesLoadingPolicy());
157+
idlWorkflowStateOptions.setWaitUntilApiTimeoutSeconds(stateOptions.getWaitUntilApiTimeoutSeconds());
158+
idlWorkflowStateOptions.setExecuteApiTimeoutSeconds(stateOptions.getExecuteApiTimeoutSeconds());
159+
idlWorkflowStateOptions.setWaitUntilApiRetryPolicy(stateOptions.getWaitUntilApiRetryPolicy());
160+
idlWorkflowStateOptions.setExecuteApiRetryPolicy(stateOptions.getExecuteApiRetryPolicy());
161+
if (stateOptions.getProceedToExecuteWhenWaitUntilRetryExhausted() != null) {
162+
idlWorkflowStateOptions.setWaitUntilApiFailurePolicy(Boolean.TRUE.equals(stateOptions.getProceedToExecuteWhenWaitUntilRetryExhausted())
163+
? WaitUntilApiFailurePolicy.PROCEED_ON_FAILURE
164+
: WaitUntilApiFailurePolicy.FAIL_WORKFLOW_ON_FAILURE);
165+
}
166+
if (stateOptions.getProceedToStateWhenExecuteRetryExhausted() != null) {
167+
idlWorkflowStateOptions.setExecuteApiFailurePolicy(ExecuteApiFailurePolicy.PROCEED_TO_CONFIGURED_STATE);
168+
idlWorkflowStateOptions.setExecuteApiFailureProceedStateId(stateOptions.getProceedToStateWhenExecuteRetryExhausted()
169+
.getSimpleName());
170+
}
171+
if (stateOptions.getProceedToStateWhenExecuteRetryExhaustedStateOptions() != null) {
172+
idlWorkflowStateOptions.setExecuteApiFailureProceedStateOptions(toIdlWorkflowStateOptionsWithValidation(
173+
stateOptions.getProceedToStateWhenExecuteRetryExhaustedStateOptions(),
174+
stateId));
175+
}
176+
177+
validateExecuteApiFailurePolicy(idlWorkflowStateOptions, stateId);
178+
validateWaitUntilApiFailurePolicy(idlWorkflowStateOptions, stateId);
179+
180+
return idlWorkflowStateOptions;
117181
}
118182
}

0 commit comments

Comments
 (0)