Better handling of zk bad version
- Remove propagating BadVersionException from ZookeeperStateMachineEnsemble via event so that machine can be kept running. Further logs are then read anyway via watcher. Thought we still need better handling but this is better for now. - Relates to #92
This commit is contained in:
@@ -18,6 +18,8 @@ package org.springframework.statemachine.test;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -112,15 +114,19 @@ public class StateMachineTestPlan<S, E> {
|
||||
}
|
||||
|
||||
if (step.sendEvent != null) {
|
||||
StateMachine<S, E> sendVia = null;
|
||||
ArrayList<StateMachine<S, E>> sendVia = new ArrayList<StateMachine<S, E>>();
|
||||
if (step.sendEventMachineId != null) {
|
||||
sendVia = stateMachines.get(step.sendEventMachineId);
|
||||
sendVia.add(stateMachines.get(step.sendEventMachineId));
|
||||
} else if (step.sendEventToAll) {
|
||||
sendVia.addAll(stateMachines.values());
|
||||
} else {
|
||||
sendVia = stateMachines.values().iterator().next();
|
||||
sendVia.add(stateMachines.values().iterator().next());
|
||||
}
|
||||
assertThat("Error finding machine to send via", sendVia, not(empty()));
|
||||
for (StateMachine<S, E> machine : sendVia) {
|
||||
log.info("Sending test event " + step.sendEvent + " via machine " + machine);
|
||||
machine.sendEvent(step.sendEvent);
|
||||
}
|
||||
assertThat("Error finding machine to send via", sendVia, notNullValue());
|
||||
log.info("Sending test event " + step.sendEvent + " via machine " + sendVia);
|
||||
sendVia.sendEvent(step.sendEvent);
|
||||
}
|
||||
|
||||
if (step.expectStateChanged != null) {
|
||||
|
||||
@@ -111,6 +111,7 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
|
||||
E sendEvent;
|
||||
Object sendEventMachineId;
|
||||
boolean sendEventToAll = false;
|
||||
final Collection<S> expectStates = new ArrayList<S>();
|
||||
Integer expectStateChanged;
|
||||
Integer expectStateEntered;
|
||||
@@ -156,7 +157,22 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
* @return the state machine test plan step builder
|
||||
*/
|
||||
public StateMachineTestPlanStepBuilder sendEvent(E event) {
|
||||
return sendEvent(event, null);
|
||||
return sendEvent(event, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an event {@code E}. If {@code sendToAll} is set to {@code TRUE} event
|
||||
* will be send to all existing machines.
|
||||
*
|
||||
* @param event the event
|
||||
* @param sendToAll send to all machines
|
||||
* @return the state machine test plan step builder
|
||||
*/
|
||||
public StateMachineTestPlanStepBuilder sendEvent(E event, boolean sendToAll) {
|
||||
this.sendEvent = event;
|
||||
this.sendEventMachineId = null;
|
||||
this.sendEventToAll = sendToAll;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,7 +346,7 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
* @return the state machine test plan builder for chaining
|
||||
*/
|
||||
public StateMachineTestPlanBuilder<S, E> and() {
|
||||
steps.add(new StateMachineTestPlanStep<S, E>(sendEvent, sendEventMachineId, expectStates,
|
||||
steps.add(new StateMachineTestPlanStep<S, E>(sendEvent, sendEventMachineId, sendEventToAll, expectStates,
|
||||
expectStateChanged, expectStateEntered, expectStateExited, expectEventNotAccepted,
|
||||
expectTransition, expectTransitionStarted, expectTransitionEnded, expectStateMachineStarted,
|
||||
expectStateMachineStopped, expectVariableKeys, expectVariables));
|
||||
@@ -342,6 +358,7 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
static class StateMachineTestPlanStep<S, E> {
|
||||
E sendEvent;
|
||||
Object sendEventMachineId;
|
||||
boolean sendEventToAll = false;
|
||||
final Collection<S> expectStates;
|
||||
Integer expectStateChanged;
|
||||
Integer expectStateEntered;
|
||||
@@ -355,13 +372,15 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
final Collection<Object> expectVariableKeys;
|
||||
final Map<Object, Object> expectVariables;
|
||||
|
||||
public StateMachineTestPlanStep(E sendEvent, Object sendEventMachineId, Collection<S> expectStates, Integer expectStateChanged,
|
||||
Integer expectStateEntered, Integer expectStateExited, Integer expectEventNotAccepted,
|
||||
Integer expectTransition, Integer expectTransitionStarted, Integer expectTransitionEnded,
|
||||
Integer expectStateMachineStarted, Integer expectStateMachineStopped,
|
||||
Collection<Object> expectVariableKeys, Map<Object, Object> expectVariables) {
|
||||
public StateMachineTestPlanStep(E sendEvent, Object sendEventMachineId, boolean sendEventToAll,
|
||||
Collection<S> expectStates, Integer expectStateChanged, Integer expectStateEntered,
|
||||
Integer expectStateExited, Integer expectEventNotAccepted, Integer expectTransition,
|
||||
Integer expectTransitionStarted, Integer expectTransitionEnded, Integer expectStateMachineStarted,
|
||||
Integer expectStateMachineStopped, Collection<Object> expectVariableKeys,
|
||||
Map<Object, Object> expectVariables) {
|
||||
this.sendEvent = sendEvent;
|
||||
this.sendEventMachineId = sendEventMachineId;
|
||||
this.sendEventToAll = sendEventToAll;
|
||||
this.expectStates = expectStates;
|
||||
this.expectStateChanged = expectStateChanged;
|
||||
this.expectStateEntered = expectStateEntered;
|
||||
|
||||
@@ -32,7 +32,6 @@ import org.apache.curator.framework.imps.CuratorFrameworkState;
|
||||
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
|
||||
import org.apache.curator.framework.recipes.nodes.PersistentEphemeralNode;
|
||||
import org.apache.curator.framework.recipes.nodes.PersistentEphemeralNode.Mode;
|
||||
import org.apache.zookeeper.KeeperException;
|
||||
import org.apache.zookeeper.WatchedEvent;
|
||||
import org.apache.zookeeper.data.Stat;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
@@ -189,12 +188,6 @@ public class ZookeeperStateMachineEnsemble<S, E> extends StateMachineEnsembleObj
|
||||
persist.write(context, stat);
|
||||
stateRef.set(new StateWrapper(context, stat.getVersion()));
|
||||
} catch (Exception e) {
|
||||
if (e instanceof StateMachineException) {
|
||||
if (((StateMachineException)e).contains(KeeperException.BadVersionException.class)) {
|
||||
notifyError(new StateMachineEnsembleException("Cas error during write id=[" + uuid
|
||||
+ "] for context=[" + context + "]", e));
|
||||
}
|
||||
}
|
||||
throw new StateMachineException("Error persisting data", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,6 +257,51 @@ public class ZookeeperStateMachineTests extends AbstractZookeeperTests {
|
||||
plan.test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHaveCasErrorDoesNotBreakMachines() throws Exception {
|
||||
context.register(ZkServerConfig.class, BaseConfig.class);
|
||||
context.refresh();
|
||||
|
||||
CuratorFramework curatorClient =
|
||||
context.getBean("curatorClient", CuratorFramework.class);
|
||||
|
||||
StateMachine<String, String> machine1 =
|
||||
buildTestStateMachine2(curatorClient);
|
||||
StateMachine<String, String> machine2 =
|
||||
buildTestStateMachine2(curatorClient);
|
||||
StateMachine<String, String> machine3 =
|
||||
buildTestStateMachine2(curatorClient);
|
||||
StateMachine<String, String> machine4 =
|
||||
buildTestStateMachine2(curatorClient);
|
||||
StateMachine<String, String> machine5 =
|
||||
buildTestStateMachine2(curatorClient);
|
||||
|
||||
StateMachineTestPlan<String, String> plan =
|
||||
StateMachineTestPlanBuilder.<String, String>builder()
|
||||
.defaultAwaitTime(2)
|
||||
.stateMachine(machine1)
|
||||
.stateMachine(machine2)
|
||||
.stateMachine(machine3)
|
||||
.stateMachine(machine4)
|
||||
.stateMachine(machine5)
|
||||
.step()
|
||||
.expectStates("SI")
|
||||
.and()
|
||||
.step()
|
||||
.sendEvent("E1", true)
|
||||
.expectStateChanged(1)
|
||||
.expectStates("S1")
|
||||
.and()
|
||||
.step()
|
||||
.sendEvent("E2", true)
|
||||
.expectStateChanged(1)
|
||||
.expectStates("S2")
|
||||
.and()
|
||||
.build();
|
||||
|
||||
plan.test();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testJoinLaterShouldSyncState() throws Exception {
|
||||
@@ -550,6 +595,34 @@ public class ZookeeperStateMachineTests extends AbstractZookeeperTests {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private StateMachine<String, String> buildTestStateMachine2(CuratorFramework curatorClient)
|
||||
throws Exception {
|
||||
StateMachineBuilder.Builder<String, String> builder = StateMachineBuilder.builder();
|
||||
|
||||
builder.configureConfiguration()
|
||||
.withConfiguration()
|
||||
.taskExecutor(new SyncTaskExecutor())
|
||||
.autoStartup(true)
|
||||
.and()
|
||||
.withDistributed()
|
||||
.ensemble(stateMachineEnsemble(curatorClient));
|
||||
|
||||
builder.configureStates()
|
||||
.withStates()
|
||||
.initial("SI")
|
||||
.state("S1")
|
||||
.state("S2");
|
||||
|
||||
builder.configureTransitions()
|
||||
.withExternal()
|
||||
.source("SI").target("S1").event("E1")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S1").target("S2").event("E2");
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static FooGuard foo0Guard() {
|
||||
return new FooGuard(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user