Reputation: 51
I am trying to create a few instances of state machine from one uml-model. I use stateMachineFactory. I would like these machines working independently and asynchrously.
Everything work great if I use only "base" states. Machine instances can independently go to stateB and StateC. However, when I use regions and sub-states (stateD), machine instances execute action (insideStateD1) one after another. Please look at .
I've found that states are executed via stateMachineTaskExecutor (which default is SyncTaskExecutor) but substates are executed via taskScheduler (which default is ConcurrentTaskScheduler).
This is configuration:
@Configuration
@EnableStateMachineFactory
public class StateMachineConfig extends StateMachineConfigurerAdapter<String, String> {
@Autowired
StateMachineComponentResolver<String, String> stateMachineComponentResolver;
@Bean
public StateMachineModelFactory<String, String> modelFactory() {
UmlStateMachineModelFactory umlStateMachineModelFactory = new UmlStateMachineModelFactory("classpath:uml/testSM1.uml");
umlStateMachineModelFactory.setStateMachineComponentResolver(stateMachineComponentResolver);
return umlStateMachineModelFactory;
}
@Override
public void configure(StateMachineModelConfigurer<String, String> model) throws Exception {
model
.withModel()
.factory(modelFactory());
}
@Override
public void configure(StateMachineConfigurationConfigurer<String, String> config) throws Exception {
config
.withConfiguration()
// .taskExecutor() // I tried various taskExecutors
// .taskScheduler() // I tried various taskSchedulers
;
}
}
What is the correct way to achieve many instances of state machine from the same model?
Upvotes: 4
Views: 2061
Reputation: 31473
Multiple instances of a SM can be obtained by the StateMachineFactory.
stateMachineFactory.getStateMachine(); //builds a new state machine
The configuration that you have created in StateMachineConfig applies to all SM instances.
Spring State Machine uses TaskExecutor
for region executions (doesn't matter top level or nested regions) and by default it's synchronous. To achieve async execution you need to override the default task executor. This can be achieved in the configuration:
@Override
public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception {
config
.withConfiguration()
//other configs
.taskExecutor(myAsyncTaskExecutor())
}
public TaskExecutor myAsyncTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
return taskExecutor;
}
or by declaring a bean:
@Bean(name = StateMachineSystemConstants.TASK_EXECUTOR_BEAN_NAME)
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
return taskExecutor;
}
TaskScheduler
is used for action executions (actions associated with states or transitions) and not for sub-states.
Upvotes: 1