¿Cómo restaurar la máquina de estado desde el contexto creado en tiempo de ejecución?

Resuelto jonua asked hace 5 años • 1 respuestas

tengo una maquina de estados

@EnableStateMachine
@Configuration
public class StateMachineConfiguration extends EnumStateMachineConfigurerAdapter<Status, Event> {
    @Override
    public void configure(StateMachineStateConfigurer<Status, Event> states) throws Exception {
        states.withStates()
                .initial(Status.DRAFT)
                .states(EnumSet.allOf(Status.class));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<Status, Event> transitions) throws Exception {
        transitions

                .withExternal()
                .target(Status.INVITATION).source(Status.DRAFT)
                .event(Event.INVITED)
                .guard(new Guard())
                .action(new ActionInvited())
                .and()

                .withExternal()
                .target(Status.DECLINED).source(Status.INVITATION)
                .event(Event.DECLINED)
                .action(new ActionDeclined());
    }

    @Override
    public void configure(StateMachineConfigurationConfigurer<Status, Event> config) throws Exception {
        config.withConfiguration().autoStartup(true);
    }
}

y tengo un modelo, por ejemplo Order . El modelo persiste en la base de datos. Extraigo el modelo de la base de datos, ahora mi modelo tiene un estado Order.status == INVITATION. Quiero continuar procesando el modelo con statemachine, pero la instancia de statemachine comenzará a procesarse con el estado inicial BORRADOR pero necesito continuar procesando desde el estado INVITACIÓN . En otras palabras quiero ejecutar

stateMachine.sendEvent(MessageBuilder
  .withPayload(Event.DECLINED)
  .setHeader("orderId", order.id)
  .build()
)

y ejecutar la acción ActionDeclined(). No quiero conservar un contexto de máquina de estado en la base de datos. Quiero establecer un estado de stateMachine en el estado de mi modelo en tiempo de ejecución. ¿Cómo puedo hacer eso de la manera correcta? ¿Usar el constructor DefaultStateContext o tener otra forma más hermosa?

jonua avatar Feb 15 '19 16:02 jonua
Aceptado

Un enfoque posible es crear el archivo StateMachinesobre la marcha y rehidratar la máquina de estado desde la base de datos utilizando el estado del archivo Order. En este caso es necesario realizar los siguientes pasos:

  • Restableciendo el StateMachineen todas las regiones
  • Estado de carga Orderdesde la base de datos
  • Crear nuevo DefaultStateMachineContexty completar en consecuencia

Supongamos que tiene un método de compilación que devuelve nuevas máquinas de estado para procesar eventos de orden (usando StateMachineFactory ) , pero para una orden existente, rehidratará el estado de la base de datos.

StateMachine<Status, Event> build(long orderId) {
  orderService.getOrder(orderId) //returns Optional
  .map(order -> {
     StateMachine<Status, Event> sm = stateMachineFactory.getStateMachine(Long.toString(orderId));
     sm.stop();
     rehydrateState(sm, sm.getExtendedState(), order.getStatus());
     sm.start();
     return sm;
   })
  .orElseGet(() -> createNewStateMachine(orderId);
}


void rehydrateState(StateMachine<Status, Event> newStateMachine, ExtendedState extendedState, Status orderStatus) {
  newStateMachine.getStateMachineAccessor().doWithAllRegions(sma ->
   sma.resetStateMachine(new DefaultStateMachineContext<>(orderStatus, null, null, extendedState));
  });
}
hovanessyan avatar Feb 15 '2019 10:02 hovanessyan