Skaikru87
Skaikru87

Reputation: 51

Asynchronous execution of sub-states in parallel instances of spring state machine

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 diagram][1.

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

Answers (1)

hovanessyan
hovanessyan

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

Related Questions