私のマルチユーザ環境でも同じ問題がありました。レシピの概念は実際には機能しません。すべての要求に対してただ1つのステートマシンを使用することは、スレッドセーフではありません。 PersistStateMachineHandlerのスタイルで独自のクラスを作成しましたが、特定のStateMachineではなく、特定のStateMachineFactoryを使用して独自のクラスを作成しました。
public class PersistentStateMachineHandler<S, T> {
private final StateMachineFactory<S, T> stateMachineFactory;
private final PersistingStateChangeInterceptor<S, T> interceptor = new PersistingStateChangeInterceptor<>();
private final CompositePersistStateChangeListener<S, T> listeners = new CompositePersistStateChangeListener<>();
public PersistentStateMachineHandler(StateMachineFactory<S, T> stateMachineFactory) {
this.stateMachineFactory = stateMachineFactory;
}
public void addPersistentStateChangeListener(PersistentStateChangeListener<S, T> persistentStateChangeListener) {
listeners.register(persistentStateChangeListener);
}
public boolean handleEventWithState(Map<Object, Object> variables, S state, T event) {
StateMachine<S, T> stateMachine = stateMachineFactory.getStateMachine();
stateMachine.getStateMachineAccessor().doWithAllRegions(function -> function.addStateMachineInterceptor(interceptor));
if (state == null) {
state = stateMachine.getInitialState().getId();
}
ExtendedState extendedState = new DefaultExtendedState(variables);
List<StateMachineAccess<S, T>> withAllRegions = stateMachine.getStateMachineAccessor().withAllRegions();
for (StateMachineAccess<S, T> a : withAllRegions) {
a.resetStateMachine(new DefaultStateMachineContext<S, T>(state, null, null, extendedState));
}
stateMachine.start();
return stateMachine.sendEvent(event);
}
public interface PersistentStateChangeListener<S, T> {
void persist(State<S, T> state, Message<T> message, Transition<S, T> transition, StateMachine<S, T> stateMachine);
}
private class PersistingStateChangeInterceptor<X, Y> extends StateMachineInterceptorAdapter<S, T> {
@Override
public void preStateChange(State<S, T> state, Message<T> message, Transition<S, T> transition, StateMachine<S, T> stateMachine) {
listeners.persist(state, message, transition, stateMachine);
}
}
private class CompositePersistStateChangeListener<X, Y> extends AbstractCompositeListener<PersistentStateChangeListener<S, T>> implements
PersistentStateChangeListener<S, T> {
@Override
public void persist(State<S, T> state, Message<T> message, Transition<S, T> transition, StateMachine<S, T> stateMachine) {
for (Iterator<PersistentStateChangeListener<S, T>> iterator = getListeners().reverse(); iterator.hasNext();) {
PersistentStateChangeListener<S, T> listener = iterator.next();
listener.persist(state, message, transition, stateMachine);
}
}
}
}
春のレシピの実装に比べて、私の実装では他の二つの利点があります。
- この実装は列挙だけでなく文字列
- と実装で使用することができる状態は、イベントのメッセージで運ばれていないため、タイマによる状態変化をトリガする状態マシンで使用することができステートマシン自体のextendedStateを使用します。
確かに、イベントごとに新しいステートマシンが作成されますが、既存のステートマシンがまだアクティブな場合(非同期タスクが実行され、タイマーが実行されているなど)は判断できませんでした。これを判断する方法が見つかると、代わりに状態マシンのプールを使用することができます。