Skip to content

Commit db7f7c7

Browse files
Fix filling stateOptions for failure proceeding state (#211)
1 parent b87c388 commit db7f7c7

13 files changed

+143
-16
lines changed

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ signing {
161161
}
162162

163163
group = "io.iworkflow"
164-
version = "2.4.0"
164+
version = "2.5.1"
165165

166166
nexusPublishing {
167167
repositories {

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

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.iworkflow.core;
22

3+
import io.iworkflow.core.mapper.StateMovementMapper;
34
import io.iworkflow.core.persistence.PersistenceOptions;
5+
import io.iworkflow.gen.models.ExecuteApiFailurePolicy;
46
import io.iworkflow.gen.models.KeyValue;
57
import io.iworkflow.gen.models.SearchAttribute;
68
import io.iworkflow.gen.models.SearchAttributeKeyAndType;
@@ -153,6 +155,9 @@ public String startWorkflow(
153155
stateOptions.skipWaitUntil(true);
154156
}
155157
}
158+
159+
StateMovementMapper.autoFillFailureProceedingStateOptions(stateOptions, wfType, registry);
160+
156161
if (stateOptions != null) {
157162
unregisterWorkflowOptions.startStateOptions(stateOptions);
158163
}

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

+32
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import io.iworkflow.core.ObjectEncoder;
44
import io.iworkflow.core.Registry;
55
import io.iworkflow.core.StateDef;
6+
import io.iworkflow.core.WorkflowDefinitionException;
7+
import io.iworkflow.gen.models.ExecuteApiFailurePolicy;
68
import io.iworkflow.gen.models.StateMovement;
79
import io.iworkflow.gen.models.WorkflowStateOptions;
810

@@ -36,10 +38,40 @@ public static StateMovement toGenerated(final io.iworkflow.core.StateMovement st
3638
stateOptions.skipWaitUntil(true);
3739
}
3840

41+
autoFillFailureProceedingStateOptions(stateOptions, workflowType, registry);
42+
3943
if (stateOptions != null) {
4044
movement.stateOptions(stateOptions);
4145
}
4246
}
4347
return movement;
4448
}
49+
50+
public static void autoFillFailureProceedingStateOptions(WorkflowStateOptions stateOptions, final String workflowType, final Registry registry) {
51+
if (stateOptions == null) {
52+
return;
53+
}
54+
if (stateOptions.getExecuteApiFailurePolicy() == ExecuteApiFailurePolicy.PROCEED_TO_CONFIGURED_STATE
55+
&& stateOptions.getExecuteApiFailureProceedStateOptions() == null) {
56+
57+
// fill the state options for the proceeding state
58+
String proceedStateId = stateOptions.getExecuteApiFailureProceedStateId();
59+
final StateDef proceedStatDef = registry.getWorkflowState(workflowType, proceedStateId);
60+
WorkflowStateOptions proceedStateOptions = proceedStatDef.getWorkflowState().getStateOptions();
61+
if (proceedStateOptions != null &&
62+
proceedStateOptions.getExecuteApiFailurePolicy() == ExecuteApiFailurePolicy.PROCEED_TO_CONFIGURED_STATE) {
63+
throw new WorkflowDefinitionException("nested failure handling is not supported. You cannot set a failure proceeding state on top of another failure proceeding state.");
64+
}
65+
66+
if (shouldSkipWaitUntil(proceedStatDef.getWorkflowState())) {
67+
if (proceedStateOptions == null) {
68+
proceedStateOptions = new WorkflowStateOptions().skipWaitUntil(true);
69+
} else {
70+
proceedStateOptions.skipWaitUntil(true);
71+
}
72+
}
73+
74+
stateOptions.executeApiFailureProceedStateOptions(proceedStateOptions);
75+
}
76+
}
4577
}

src/test/java/io/iworkflow/integ/StateRecoveryTest.java

+18-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
import io.iworkflow.core.Client;
44
import io.iworkflow.core.ClientOptions;
5-
import io.iworkflow.integ.stateapifail.ExecuteApiFailProceedWorkflow;
5+
import io.iworkflow.integ.stateapifail.WorkflowStateFailProceedToRecover;
6+
import io.iworkflow.integ.stateapifail.WorkflowStateFailProceedToRecoverNoWaitUntil;
67
import io.iworkflow.spring.TestSingletonWorkerService;
78
import io.iworkflow.spring.controller.WorkflowRegistry;
89
import org.junit.jupiter.api.Assertions;
@@ -26,10 +27,24 @@ public void testStateApiFailAndRecoveryWorkflow() throws InterruptedException {
2627
final Integer input = 5;
2728

2829
client.startWorkflow(
29-
ExecuteApiFailProceedWorkflow.class, wfId, 10, input);
30+
WorkflowStateFailProceedToRecover.class, wfId, 10, input);
3031

3132
Integer output = client.getSimpleWorkflowResultWithWait(Integer.class, wfId);
32-
Assertions.assertEquals(5, output);
33+
Assertions.assertEquals(10, output);
34+
}
35+
36+
@Test
37+
public void testStateApiFailAndRecoveryNoWaitUntilWorkflow() throws InterruptedException {
38+
final Client client = new Client(WorkflowRegistry.registry, ClientOptions.localDefault);
39+
final long startTs = System.currentTimeMillis();
40+
final String wfId = "testStateApiFailAndRecoveryNoWaitUntilWorkflow" + startTs / 1000;
41+
final Integer input = 5;
42+
43+
client.startWorkflow(
44+
WorkflowStateFailProceedToRecoverNoWaitUntil.class, wfId, 10, input);
45+
46+
Integer output = client.getSimpleWorkflowResultWithWait(Integer.class, wfId);
47+
Assertions.assertEquals(10, output);
3348
}
3449

3550
}

src/test/java/io/iworkflow/integ/WorkflowUncompletedTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import io.iworkflow.gen.models.WorkflowStopType;
88
import io.iworkflow.integ.forcefail.ForceFailWorkflow;
99
import io.iworkflow.integ.signal.BasicSignalWorkflow;
10-
import io.iworkflow.integ.stateapifail.StateApiFailWorkflow;
10+
import io.iworkflow.integ.stateapifail.WorkflowBasicStateFail;
1111
import io.iworkflow.integ.stateapitimeout.StateApiTimeoutFailWorkflow;
1212
import io.iworkflow.spring.TestSingletonWorkerService;
1313
import io.iworkflow.spring.controller.WorkflowRegistry;
@@ -203,7 +203,7 @@ public void testStateApiFailWorkflow() throws InterruptedException {
203203
final Integer input = 5;
204204

205205
final String runId = client.startWorkflow(
206-
StateApiFailWorkflow.class, wfId, 10, input);
206+
WorkflowBasicStateFail.class, wfId, 10, input);
207207

208208
try {
209209
client.getSimpleWorkflowResultWithWait(Integer.class, wfId);

src/test/java/io/iworkflow/integ/stateapifail/StateApiFailWorkflowState1.java renamed to src/test/java/io/iworkflow/integ/stateapifail/StateFailBasic.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import io.iworkflow.gen.models.RetryPolicy;
1111
import io.iworkflow.gen.models.WorkflowStateOptions;
1212

13-
public class StateApiFailWorkflowState1 implements WorkflowState<Integer> {
13+
public class StateFailBasic implements WorkflowState<Integer> {
1414

1515
@Override
1616
public Class<Integer> getInputType() {

src/test/java/io/iworkflow/integ/stateapifail/StateApiFailProceedState.java renamed to src/test/java/io/iworkflow/integ/stateapifail/StateFailProceedToRecoverBasic.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
import io.iworkflow.gen.models.RetryPolicy;
55
import io.iworkflow.gen.models.WorkflowStateOptions;
66

7-
public class StateApiFailProceedState extends StateApiFailWorkflowState1 {
7+
public class StateFailProceedToRecoverBasic extends StateFailBasic {
88
@Override
99
public WorkflowStateOptions getStateOptions() {
1010
return new WorkflowStateOptionsExtension()
11-
.setProceedOnExecuteFailure(StateApiRecoverState.class)
11+
.setProceedOnExecuteFailure(StateRecoverBasic.class)
1212
.executeApiRetryPolicy(
1313
new RetryPolicy()
1414
.maximumAttempts(1)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.iworkflow.integ.stateapifail;
2+
3+
import io.iworkflow.core.WorkflowStateOptionsExtension;
4+
import io.iworkflow.gen.models.RetryPolicy;
5+
import io.iworkflow.gen.models.WorkflowStateOptions;
6+
7+
public class StateFailProceedToRecoverNoWaitUntil extends StateFailBasic {
8+
@Override
9+
public WorkflowStateOptions getStateOptions() {
10+
return new WorkflowStateOptionsExtension()
11+
.setProceedOnExecuteFailure(StateRecoverNoWaitUntil.class)
12+
.executeApiRetryPolicy(
13+
new RetryPolicy()
14+
.maximumAttempts(1)
15+
.backoffCoefficient(2f)
16+
);
17+
}
18+
}

src/test/java/io/iworkflow/integ/stateapifail/StateApiRecoverState.java renamed to src/test/java/io/iworkflow/integ/stateapifail/StateRecoverBasic.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import io.iworkflow.core.communication.Communication;
99
import io.iworkflow.core.persistence.Persistence;
1010

11-
public class StateApiRecoverState implements WorkflowState<Integer> {
11+
public class StateRecoverBasic implements WorkflowState<Integer> {
1212

1313
@Override
1414
public Class<Integer> getInputType() {
@@ -31,6 +31,12 @@ public StateDecision execute(
3131
CommandResults commandResults,
3232
Persistence persistence,
3333
final Communication communication) {
34-
return StateDecision.gracefulCompleteWorkflow(input);
34+
if(input == 10){
35+
return StateDecision.gracefulCompleteWorkflow(input);
36+
}else if(input == 5){
37+
return StateDecision.singleNextState(StateFailProceedToRecoverBasic.class, input * 2);
38+
}else{
39+
return StateDecision.forceFailWorkflow("unexpected input "+input);
40+
}
3541
}
3642
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package io.iworkflow.integ.stateapifail;
2+
3+
import io.iworkflow.core.Context;
4+
import io.iworkflow.core.StateDecision;
5+
import io.iworkflow.core.WorkflowState;
6+
import io.iworkflow.core.command.CommandResults;
7+
import io.iworkflow.core.communication.Communication;
8+
import io.iworkflow.core.persistence.Persistence;
9+
10+
public class StateRecoverNoWaitUntil implements WorkflowState<Integer> {
11+
12+
@Override
13+
public Class<Integer> getInputType() {
14+
return Integer.class;
15+
}
16+
17+
@Override
18+
public StateDecision execute(
19+
Context context,
20+
Integer input,
21+
CommandResults commandResults,
22+
Persistence persistence,
23+
final Communication communication) {
24+
if(input == 10){
25+
return StateDecision.gracefulCompleteWorkflow(input);
26+
}else if(input == 5){
27+
return StateDecision.singleNextState(StateFailProceedToRecoverNoWaitUntil.class, input * 2);
28+
}else{
29+
return StateDecision.forceFailWorkflow("unexpected input "+input);
30+
}
31+
}
32+
}

src/test/java/io/iworkflow/integ/stateapifail/StateApiFailWorkflow.java renamed to src/test/java/io/iworkflow/integ/stateapifail/WorkflowBasicStateFail.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
import java.util.List;
99

1010
@Component
11-
public class StateApiFailWorkflow implements ObjectWorkflow {
11+
public class WorkflowBasicStateFail implements ObjectWorkflow {
1212
@Override
1313
public List<StateDef> getWorkflowStates() {
1414
return Arrays.asList(
15-
StateDef.startingState(new StateApiFailWorkflowState1())
15+
StateDef.startingState(new StateFailBasic())
1616
);
1717
}
1818
}

src/test/java/io/iworkflow/integ/stateapifail/ExecuteApiFailProceedWorkflow.java renamed to src/test/java/io/iworkflow/integ/stateapifail/WorkflowStateFailProceedToRecover.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
import java.util.List;
99

1010
@Component
11-
public class ExecuteApiFailProceedWorkflow implements ObjectWorkflow {
11+
public class WorkflowStateFailProceedToRecover implements ObjectWorkflow {
1212
@Override
1313
public List<StateDef> getWorkflowStates() {
1414
return Arrays.asList(
15-
StateDef.startingState(new StateApiFailProceedState()),
16-
StateDef.nonStartingState(new StateApiRecoverState())
15+
StateDef.startingState(new StateFailProceedToRecoverBasic()),
16+
StateDef.nonStartingState(new StateRecoverBasic())
1717
);
1818
}
1919
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.iworkflow.integ.stateapifail;
2+
3+
import io.iworkflow.core.ObjectWorkflow;
4+
import io.iworkflow.core.StateDef;
5+
import org.springframework.stereotype.Component;
6+
7+
import java.util.Arrays;
8+
import java.util.List;
9+
10+
@Component
11+
public class WorkflowStateFailProceedToRecoverNoWaitUntil implements ObjectWorkflow {
12+
@Override
13+
public List<StateDef> getWorkflowStates() {
14+
return Arrays.asList(
15+
StateDef.startingState(new StateFailProceedToRecoverNoWaitUntil()),
16+
StateDef.nonStartingState(new StateRecoverNoWaitUntil())
17+
);
18+
}
19+
}

0 commit comments

Comments
 (0)