Skip to content

Timing issue when using a Factory with async taskexecutor #298

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

Closed
cvwj opened this issue Dec 28, 2016 · 3 comments
Closed

Timing issue when using a Factory with async taskexecutor #298

cvwj opened this issue Dec 28, 2016 · 3 comments
Labels
type/bug Is a bug report
Milestone

Comments

@cvwj
Copy link

cvwj commented Dec 28, 2016

I use the SSM 1.2.0.RELEASE together with Spring Boot 2.0.0.BUILD-SNAPSHOT.

In my setup, I start a new State Machine instance every time I receive a request. I'm using a StateMachineFactory to get a machine. The Factory is configured like this:

    @Override
    public void configure(StateMachineConfigurationConfigurer<String, String> config) throws Exception {
        config
                .withConfiguration()
                .autoStartup(true)
                .taskExecutor(new SimpleAsyncTaskExecutor());
    }

When the request arrives in my REST service, I do this:

        StateMachine<String, String> machine = leadAMachineFactory.getStateMachine();
        Message<String> leadMessage = MessageBuilder
                .withPayload("lead_arrived")
                .setHeader("lead", leadA)
                .build();

        machine.sendEvent(leadMessage);

This results in a NullPointerException in AbstractStateMachine.acceptEvent(). The reason is that the machine.currentState is null when I send the Event to it. It is not finished initialising.

If I instead wait with sending the event until machine is in a valid state, everything works fine:

        StateMachine<String, String> machine = leadAMachineFactory.getStateMachine();
        Message<String> leadMessage = MessageBuilder
                .withPayload("lead_arrived")
                .setHeader("lead", leadA)
                .build();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (machine.getState() == null) {
                    try {
                        System.out.println("Machine not ready...");
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                machine.sendEvent(leadMessage);
            }
        }).start();

If the Factory is configured with a Synchronous task Executor like the default one, there are also no problems, as the sendEvent statement is executed in the same thread, but at a later point than the initialising code.

One (naive?) solution could be to block the sendEvent() until the machine is in a ready condition.

@jvalkeal
Copy link
Contributor

Thanks for pointing this out. I'll poke around to find some kind of fix for this. In a meanwhile I suppose starting machine manually and using StateMachineListener to know when started event is send would do a trick.

I'm also thinking that if autostart is used then maybe internal factory should should not return a machine before it is started. That said, user should not have to worry about these things.

@jvalkeal jvalkeal added the type/bug Is a bug report label Dec 28, 2016
@jvalkeal jvalkeal added this to the 1.2.1.RELEASE milestone Dec 28, 2016
@jvalkeal
Copy link
Contributor

When we find a good fix for 1.2.1 it's definitely something to backport to 1.1.x.

jvalkeal added a commit to jvalkeal/spring-statemachine that referenced this issue Dec 29, 2016
- Factory now listens machine event if autostart
  is requested which should give fully started machine
  i.e. if asynch executor is used. Bails out after 30
  seconds. Further tweaks like allowing user to define
  this time or conditionally not wait could be added later.
- Fix typos.
- Fixes spring-projects#298
@jvalkeal
Copy link
Contributor

Fixed per 8bb852c in branch 1.2.x.

jvalkeal added a commit that referenced this issue Jan 18, 2017
- Backport #298
- Factory now listens machine event if autostart
  is requested which should give fully started machine
  i.e. if asynch executor is used. Bails out after 30
  seconds. Further tweaks like allowing user to define
  this time or conditionally not wait could be added later.
- Fix typos.
- Relates to #307
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/bug Is a bug report
Projects
None yet
Development

No branches or pull requests

2 participants