spring-projects / spring-statemachine

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

How to correctly manage the life cycle of multiple entities using the spring state machine #528

Open swsms opened 6 years ago

swsms commented 6 years ago

Hello, I'd like to ask you how to correctly manage the lifecycle of multiple entities using the spring state machine.

Almost every system I write has an entity with its own lifecycle (tasks, payments and so on). I'd like to manage the lifecycle of entities (transitions, guard conditions) using the spring state machine. But I see the framework is often used to manage the state of whole applications, not individual entities.

In general, I want to have the following behaviour.

1) My application receives an HTTP request through an API to modify one entity (to change its state and perform an additional logic). 2) Load the corresponding entity from DB (for instance, relational). The loaded entity has a state. 3) Initialize a new state machine instance (or from a pool) with the state. 4) Try to perform an action to change to another state. 5) If 4 is successful then store the new state of my entity in DB together with some additional data in the same transaction, otherwise, it should not change the state. 6) Return an HTTP response with the result of the operation.

My question is can I load a new state machine per request and then initialize it with an entity state? I would like to store the state in a relational database as a part of my entity. But I do not want to store the description of the state machine itself (possible states, transitions, events) as shown here.

The system will process a lot of requests, so, it needs a lot of state machines. Are there some best practice to work with the state machine in this case?

It seems, I found a project on GitHub, which is probably closer to my wishes. But I would like to try the standard spring framework for state machines.

Sorry, if this is an obvious question. I recently started using Spring after EJB. There I wrote something similar from scratch using @Stateless beans (per request). A bean kept only possible transitions and logic to check data between transitions (guards). The current state of an entity was stored in the DB. It also represents the current state of a state machine after loading the entity.

Thx.

rgreig commented 6 years ago

Hi - I think that many people have the same use case. We have it too and use statemachine successfully for this (which I'll describe). Our use case is to use spring statemachine (+ other libs) to provide a compelling alternative to hideous BPM products.

I think you are right in your observation that the framework seems to be designed from the perspective of having a very small number of state machines in an app, essentially running core app logic. But with a relatively small amount of work you can make it work. The odd thing from my experience is that the use case I have is the one that I think is far more common than the one where you just run a few instances. What we did was the following:

The great thing about the spring state machine is that it is based on UML 2.x stateflow which is pretty comprehensive (albeit vague in places). You could definitely use it as a full replacement for BPM. The diagram notation is useful as a documentation aid and is supported by various tools to varying degrees.

The area that we need to work on some more is clustering. You really need a partitioned cluster to be able to scale this out (e.g. Akka partitioned cluster would be ideal). Zookeeper is another option but is more of a pain. Would welcome thoughts or ideas.

olle commented 6 years ago

Wow @rgreig thanks for your insights, as it turns out we're about to embark on a simliar mission - and we're doing our utmost to avoid any BPM product, in the stricter sense.

It still feels a bit clunky though, but we'll give it a try.

Your tip about versioning is a great save to consider early. Thanks!

Rapster commented 2 years ago

Reviving this post after so long, but this topic sounds quite recurrent (here and there I'm facing the same "issue". Looking at this video https://www.youtube.com/watch?v=M4Aa45Gpc4w it seems the author is creating a new state machine per order, and forces to stop/start the FSM but I don't think the code looks straightforward. Basically, I feel what the library needs is a stateless FSM so it can simply drive the state of an entity (e.g Order) from one state to another and that same FSM could be reused for other entities. Maybe that post would explain it better than I do :D @jvalkeal What do you think?