spring-projects / spring-statemachine

Spring Statemachine is a framework for application developers to use state machine concepts with Spring.
1.57k stars 616 forks source link

Approach validity check #717

Open nnurmano opened 5 years ago

nnurmano commented 5 years ago

I would like to achieve the following. I have a statemachine configured in the database, the machineId is "order_management". At the same time, I would like to persist the state of the machine in the database, with some order ID. The scenario is to restore the machine if there is a persisted context or use vanilla "order_management" machine otherwise. Currently, I use write and read methods to persist the context and read the context from the database.

This seemed simple until I discovered that I needed to pass order ID parameter to read method with contextObj parameter, but this parameter is effectively a machineId. So I have to pass either machineId ("order_management") or some ID, which is not helpful for my scenario.

Is it possible to pass an object as contextObj to read method of StateMachinePersist?

I would like to pass {"process":"order_management", "instanceId":10002} to read method as contextObj, is this possible?

jvalkeal commented 5 years ago

What goes into a database is really internal representation of a machine state thus you can't biggybag into those structures. Maybe you could just use that instanceId as a machine id?

nnurmano commented 5 years ago

Thanks for the comment. My use case is as follows. Let's say, I would like to have two statemachines which serve different purposes, order management and ticket management. This requires that I have to store two different configurations in the database. When I would like to initialize a workflow, there is no an instance id, thus I have to use some generic id, which is "order_managment" or "ticket_management". And if a workflow has already been initialized and saved, then I restore the state with an instance id. The bottomline is, I have to overload acquireStateMachine method to add

public StateMachine<S, E> acquireStateMachine(String machineId, Long instanceId, boolean start) {
        log.info("Acquiring machine with id " + machineId);
        synchronized (machines) {
            StateMachine<S, E> stateMachine = machines.get(machineId);
            if (stateMachine == null) {
                log.info("Getting new machine from factory with id " + machineId);
                stateMachine = stateMachineFactory.getStateMachine(machineId);
                if (stateMachinePersist != null) {
                    try {
                        StateMachineContext<S, E> stateMachineContext;
                        if (instanceId != null) {
                            stateMachineContext =
                                    stateMachinePersist.read(String.valueOf(instanceId));
                        } else {
                            stateMachineContext =
                                    stateMachinePersist.read(machineId);
                        }
                        stateMachine = restoreStateMachine(stateMachine, stateMachineContext);
                    } catch (Exception e) {
                        log.error("Error handling context", e);
                        throw new StateMachineException("Unable to read context from store", e);
                    }
                }
                machines.put(machineId, stateMachine);
            }
            return handleStart(stateMachine, start);
        }