StatesLanguage - Declaratively design state machines that compile to Elixir based :gen_statem processes with the States Language JSON specification

StatesLanguage

Declaratively design state machines that compile to Elixir based :gen_statem processes with the States Language JSON specification.

About

States Language is the JSON specification behind AWS Step Functions, a powerful way to coordinate many disparate services into a cohesive “serverless” system. This library uses the same JSON specification and compiles to Elixir based :gen_statem processes.

Why

The initial idea for the Elixir implementation came about while working on an IVR system and we wanted a way to describe “call flows” in a declarative manner. Ideally building a system on top to allow for solution engineers to visually build call flows for a client, without writing any code.

After researching the space a bit, we landed on the States Language spec and decided it was a great fit for describing state machines. With the power of Elixir macros in-hand, this library was born.

I’ve been working on this for a few months now and have found it to be a super useful way to design state machines. Using JSON as a declarative format has also opened up a lot of opportunities for sharing this structure across projects and UIs. There’s even some mix tasks to quickly output your state machines to Graphviz and DagreD3.

The Hexdocs documentation is pretty robust, but feel free to post any questions you have here.

I hope the community finds this as useful of a tool as we have.


Brought to you by Citybase


20 Likes

I’ve updated the docs a bit to be more explicit about how to follow along with the example code.

2 Likes

New Release 0.2.4

Big improvements to the JSONPath support. No breaking changes, but handles more edge cases and deeply nested structures better.

3 Likes

Really enjoying following this project and no doubt I will have use for it. Keep up the good work!

2 Likes

Thank you! I’ve found a ton of uses for it.

IVR call flows
LiveView state manager
API input normalization
Microservice orchestration

It’s great being able to vidualize your state machines, and build editors around them.

For building editors, I’ve found being able to use the JSON Schema along with JSON Schema UI for domain specific customization to be really powerful. With dropdowns for known Resource types and TransitionEvents, it’s easy to let non programmers design their state machines.

1 Like

Would you care to make a blog post with some examples? I’m considering something like this for months but still can’t quite put my finger on it.

1 Like

I’ll have a repo of a LiveView example up shortly.

I could probably put something together for an editor as well, but that’s a little more involved, so may take some time.

What would you like to see an example of?

1 Like

I’d mostly be happy to see a flow of some sort, where you can’t get to an invalid state if the previous state invariants aren’t satisfied. Doesn’t have to be complex.

I struggle with a complex DB structure in my work where too much objects in the DB can be left in an inconsistent state and something that relies on them down the line can easily break, so I am wondering if a state machine can be a frictionless solution to that.

Here’s an example repo that uses LiveView along with StatesLanguage to define a multi-step form.

In the README.md I’ve linked to a few files that I’ve commented on, hopefully it gives you a good idea of how to utilize the library.

This example does have a state that can only be reached given certain criteria.

3 Likes

This sounds quite interesting. I‘ve been looking at xstate in js a few weeks ago, which seems to be similar to this library.

It’s similar in that it uses a declarative text format to define your states and transitions. However Javascript doesn’t have gen_statem :slight_smile: And although it abstracts some of the complexities away from utilizing gen_statem, you still have complete access to all the functionality if need be.

I’m pretty excited by this - I’ll look through the examples.

I’d be interested in seeing a couple of things:

I work quite a bit with network protocols, and also with things that get serialised to disk. Having them be independent of a BEAM process and surviving serialisation make testing these things very very nice.

Maybe its already there, & I haven’t finished the examples yet. Thanks for publishing this!

3 Likes

For a visual design tool, you can actually use the AWS Step function editor. I’ll hopefully be working on an editor over the next month or so. We have one at work, but it’s not ready to open source.

Hmm, a process-less version could be really interesting. I hadn’t thought of that. I’m interested in your thoughts around it. How would it maintain it’s current state, would you rely on another process to maintain that?

I’ll dig a little more deeply into Sasa’s work for an idea.

It ends up looking a lot like pipelining, the resulting state is just a struct internally and you drop it into a variable or stash it in a file. Pattern match function calls based on the struct like usual. Then you can embed this into a :gen_tcp or :gen_udp or Connection for example.

2 Likes

I pushed out a new release the other day, 0.2.5. It includes some fixes for string based events and a Graphviz serialization fix for the string events as well.

Unfortunately I haven’t had much time to work on a web based visual editor, but with the Graphviz support, it’s a really quick way to visually validate your logic.

For the editor, I’ve been looking into https://rete.js.org/ which I think could be really cool!

Here’s a screenshot of the one I’ve built at work, it’s not drag and drop, but does allow you to CRUD states and visualize the state machine in real-time.

4 Likes

I had another request to enable serialization. The main thing that needs to be added is starting the state machine from an arbitrary state. It should be pretty easy to implement, just haven’t gotten around to it yet.

I’ve finally made some progress on an editor. It doesn’t currently output the JSON, but will be adding that soon.

here’s a quick video

and you can play with it here, https://citybaseinc.github.io/states-language-editor/

4 Likes

FYI, the JSON that’s outputted right now in the editor isn’t 100% correct. I should have time today to get it corrected, but just in-case anyone wants to play around with it, it’s not quite complete.

Added the Wait state and JSON output is correct.

1 Like

Version 0.2.8 Released

Just released version 0.2.8.

This new version sets the child_spec restart setting to :transient, which it probably should have been all along, an oversight on my part.

This release also adds the ability to override the “start” state when starting the process. This would allow you to persist the process state and data and resume where you left off at a later time. There is now an optional start option that can be passed to start_link or start. You can see it’s usage in the documentation here or in the tests here

Editor Updates

The editor allows you to paste in your JSON and reload to use a GUI editor and view the Dagre graph.

All Editor changes should be reflected in the JSON and Dagre graph immediately.

Check it out here

There’s also a default “example” state machine loaded to play around with.

2 Likes

Hey everyone, quick update. I’ve moved on from Citybase, and have moved the repo over to my account on Github, https://github.com/entropealabs/states_language

The editor has also moved. https://entropealabs.github.io/states-language-editor/

And finally, a new version 0.2.9 was pushed hex.pm to fix a bug where "End": true states were not capturing the state data that was changed in the final state resource.

2 Likes