Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfix: Saga statemachine definition json cannot enable jackson parser, and when no choice matched in choice state will throw NPE #3309

Merged
merged 8 commits into from
Dec 8, 2020
Prev Previous commit
Next Next commit
fix saga when no choice matched throw NPE bug
  • Loading branch information
long187 committed Nov 26, 2020
commit f37447074792128b827880887ac3c7f8123dbb5f
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ public enum FrameworkErrorCode {
*/
StateMachineExecutionTimeout("0421", "State machine execution timeout", "State machine execution timeout"),

/**
* State machine execution no choice matched
*/
StateMachineNoChoiceMatched("0422", "State machine no choice matched", "State machine no choice matched"),

/**
* Undefined error
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,22 @@
import java.util.List;
import java.util.Map;

import io.seata.common.exception.FrameworkErrorCode;
import io.seata.saga.engine.StateMachineConfig;
import io.seata.saga.engine.evaluation.Evaluator;
import io.seata.saga.engine.evaluation.EvaluatorFactory;
import io.seata.saga.engine.evaluation.EvaluatorFactoryManager;
import io.seata.saga.engine.exception.EngineExecutionException;
import io.seata.saga.engine.pcext.StateHandler;
import io.seata.saga.engine.pcext.StateInstruction;
import io.seata.saga.engine.pcext.utils.EngineUtils;
import io.seata.saga.engine.utils.ExceptionUtils;
import io.seata.saga.proctrl.ProcessContext;
import io.seata.saga.statelang.domain.ChoiceState;
import io.seata.saga.statelang.domain.DomainConstants;
import io.seata.saga.statelang.domain.StateMachineInstance;
import io.seata.saga.statelang.domain.impl.ChoiceStateImpl;
import org.springframework.util.StringUtils;

/**
* ChoiceState Handler
Expand Down Expand Up @@ -74,6 +79,18 @@ public void process(ProcessContext context) throws EngineExecutionException {
}
}

if (StringUtils.isEmpty(choiceState.getDefault())) {

StateMachineInstance stateMachineInstance = (StateMachineInstance)context.getVariable(
DomainConstants.VAR_NAME_STATEMACHINE_INST);

EngineExecutionException exception = ExceptionUtils.createEngineExecutionException(FrameworkErrorCode.StateMachineNoChoiceMatched, "No choice matched, maybe it is a bug. Choice state name: " + choiceState.getName(), stateMachineInstance, null);

EngineUtils.failStateMachine(context, exception);

throw exception;
}

context.setVariable(DomainConstants.VAR_NAME_CURRENT_CHOICE, choiceState.getDefault());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ public void testSimpleStateMachineWithChoice() {
System.out.println("====== cost :" + cost);
}

@Test
public void testSimpleStateMachineWithChoiceNoDefault() {

long start = System.currentTimeMillis();

Map<String, Object> paramMap = new HashMap<>();
paramMap.put("a", 3);

String stateMachineName = "simpleChoiceNoDefaultTestStateMachine";

try {
stateMachineEngine.start(stateMachineName, null, paramMap);
} catch (EngineExecutionException e) {
e.printStackTrace(System.out);
Assertions.assertNotNull(e);
wangliang181230 marked this conversation as resolved.
Show resolved Hide resolved
}
long cost = System.currentTimeMillis() - start;
System.out.println("====== cost :" + cost);
}

@Test
public void testSimpleStateMachineWithChoiceAndEnd() {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"Name": "simpleChoiceNoDefaultTestStateMachine",
"Comment": "带条件分支但没有默认分支的测试状态机定义",
"StartState": "FirstState",
"Version": "0.0.1",
"States": {
"FirstState": {
"Type": "ServiceTask",
"ServiceName": "demoService",
"ServiceMethod": "foo",
"IsForUpdate": true,
"Next": "ChoiceState"
},
"ChoiceState":{
"Type": "Choice",
"Choices":[
{
"Expression":"[a] == 1",
"Next":"SecondState"
},
{
"Expression":"[a] == 2",
"Next":"ThirdState"
}
]
},
"SecondState": {
"Type": "ServiceTask",
"ServiceName": "demoService",
"ServiceMethod": "bar"
},
"ThirdState": {
"Type": "ServiceTask",
"ServiceName": "demoService",
"ServiceMethod": "foo"
}
}
}