Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,125 | Comments: 45,492

filter by tags archive

Simple State Machine

time to read 10 min | 1964 words

Nathan has posted Simple State Machine to CodePlex, it is the first project that I am aware of that uses Rhino DSL and the techniques that I am talking about in the book.

What is impressive about this is the level of professionalism that is involved in the project. It is a full scale DSL, with all the supporting infrastructure. I spent half an hour or so going through the entire thing, and I am impressed.

Put simply, this is how I think state based work flows should be defined. I could easily see myself extending this a bit to add persistence support & integration with NServiceBus, and be done with it.

Like most state machines, it has the ideas of states, events that can cause the state to be changed, and legal transitions from state to state. You can define tasks which will be executed upon changing a state, or upon entering / leaving a certain state.

Enough talking, let us look at a reasonably complex work flow:

workflow "Order Lifecycle"

#Event & State Identifier Targets.
#This section controls which Types will be used
#to resolve Event or State names into strongly typed CLR objects.
state_identifier_target @OrderStatus
event_identifier_target @OrderEvents

#Global Actions
on_change_state      @WriteToHistory, "on_change_state"
on_workflow_start    @WriteToHistory, "on_workflow_start"
on_workflow_complete @WriteToHistory, "on_workflow_complete"

#Event Definitions
define_event  @OrderPlaced
define_event  @CreditCardApproved
define_event  @CreditCardDenied
define_event  @OrderCancelledByCustomer
define_event  @OutOfStock
define_event  @OrderStocked
define_event  @OrderShipped
define_event  @OrderReceived
define_event  @OrderLost

#State & Transition Definitions
state @AwaitingOrder:
       when @OrderPlaced              >> @AwaitingPayment

state @AwaitingPayment:
       when @CreditCardApproved       >> @AwaitingShipment
       when @CreditCardDenied         >> @OrderCancelled
       when @OrderCancelledByCustomer >> @OrderCancelled

state @AwaitingShipment:
       when @OrderCancelledByCustomer >> @OrderCancelled
       when @OutOfStock               >> @OnBackorder
       when @OrderShipped             >> @InTransit

       #Individual states can define transition events as well
       on_enter_state @WriteToHistory, "on_enter_state(AwaitingShipment)"

state @OnBackorder:
       when @OrderCancelledByCustomer >> @OrderCancelled
       when @OrderStocked             >> @AwaitingShipment

state @InTransit:
       when @OrderReceived            >> @OrderComplete
       when @OrderLost                >> @AwaitingShipment

#NOTE: State definitions without any transitions will cause
#the state machine to Complete when they are reached.
state @OrderComplete
state @OrderCancelled

Here is the demo application UI, for the order processing life cycle:


As I said, impressive.


Shawn Neal

This has me wondering if an internal DSL would be a useful component for an e-commerce shopping cart? Specifically use the DSL to calculate discounts between dependent products (buy one get one 50% off etc) and for promotion codes (promo code is good for product X, Y, Z only).

This would certainly be more flexible, but I wonder if it would be more difficult to maintain than an engine that is statically defined and driven by data. It seems some middle ground for this would be preferable, data driven, yet write the rules not in C#, but the DSL?

Also, how does deployment come into play? It would be preferable to support an XCopy style of deployment for the DSL script since I'm going to assume it would be constantly updated - several times a week.

Ayende Rahien


I would tend to say that there are several fixed actions in the system, and leave the policy to the DSL.

The DSL can be just dropped into a directory, and immediately take affect.


I keep asking myself, why create a language for every little thing?

grega g

if artist is not satisfied by any one language he should make his own.

anyway, nice work. since i battle with WF (well our company's hack of WF) i can appreciate such project. All it would need now are persistence & security.


I have been thinking about persistence, but I'm not sure what there is to persist. In WF, the object graph of the whole state machine is persisted for each instance, but i'm sure that is useful in this case. The only thing I can think of to persist other than the business objects (which I presume are persisted independently) is the current state, and I figured that generally just be another property of the domain.

Dmitriy Nagirnyak

What do you think about this state machine implemented in ECO:


Ayende Rahien

I stopped reading when I saw how many steps you need to perform there

Dmitriy Nagirnyak

It might not be so obvious because state machine in ECO is part of the UML model and requires some background in ECO Framework.

But in a short:

  1. You create a model.

  2. You define an attribute of a class that keeps current state.

  3. You define (in UML) states, transitions, guards, effects etc.

  4. You use state it in code. Like so:

order.Approve() - changes statues to Approved (if guards allow doing so).

The idea: all is defined on the UML diagram and uses Model Driven Architecture.


I'm using Rhino DSL in a migrations open source project that a friend and I are working on. I made a blog post about the first thing I used Rhino DSL to do: manage the configuration of different environments in a settings file.


Ayende Rahien

Nice, thanks for letting me know

Comment preview

Comments have been closed on this topic.


  1. RavenDB 3.5 whirl wind tour: I'll have the 3+1 goodies to go, please - 3 days from now
  2. The design of RavenDB 4.0: Voron has a one track mind - 4 days from now
  3. RavenDB 3.5 whirl wind tour: Digging deep into the internals - 5 days from now
  4. The design of RavenDB 4.0: Separation of indexes and documents - 6 days from now
  5. RavenDB 3.5 whirl wind tour: Deeper insights to indexing - 7 days from now

And 10 more posts are pending...

There are posts all the way to May 30, 2016


  1. The design of RavenDB 4.0 (14):
    05 May 2016 - Physically segregating collections
  2. RavenDB 3.5 whirl wind tour (14):
    04 May 2016 - I’ll find who is taking my I/O bandwidth and they SHALL pay
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats