I want to define a sequential transition for my spring state machine. My state transitions are A -> B -> C. My business case is as below
I have single event E for transition to B from A and there is no event for B to C. I just want to define that if at all I am in B state I should perform the necessary actions and then move to state C without any event.
Below is the code snippet that I am using
transitions.withExternal().source(A).target(B).event(E)
transitions.withExternal().source(B).target(C)
The above transitions are taking state machine to C from A but the below onStateChanged method is first detecting change from B to C and then A to B.
Are the above transitions are correct or do we need other way to define those transitions
#OnStateChanged
public void anyStateChange() {}
I went through Spring Statemachine documentation but did not find clear answers for some scenarios. I will greatly appreciate if some one can clarify my questions.
Scenario1: How to retry errors related to action failures? Lets say I have the following states S1, S2 and S3 and when we transition from S1 to S2 I want to perform action A2. If action A2 fails I want to retry it with some time intervals. Is that possible using Spring StateMachine?
Consider AWS state machine Step Functions for example. All work in the step functions States are done using Task. And Task can be configured for retry.
transitions
.withExternal()
.source(States.S1)
.target(States.S2)
.event(Events.E1)
.action(action());
Scenario 2: Lets say Statemachine has states S1, S2 and S3. The current state is S2. If the server goes down on startup will the Statemachine execution pick up from where it left off or we will have to do it all over again?
Scenario 3: When a Guard returns false (possibly because of error condition) and prevents a transition what happens next?
How to retry a failed action?
There are two types of actions in Spring State Machine - transition actions and state actions. In scenario 1 you're talking about transition action.
When you specify a transition action, you can also specify an error handler if the action fails. This is clearly documented in the spring state machine documentation.
.withExternal()
.source(States.S1)
.target(States.S2)
.event(Events.E1)
.action(action(), errorAction());
In your errorAction() method you can implement your logic.
Possible options are:
transition to an earlier state and go the same path
transition to a specific state (e.g. retry state) where you can have your retry logic (e.g. Task/Executor that retries the action N times, and transition to other states (e.g. action success => go normal flow; action failed after N retries => transition to a failure terminal state)
There's also the official Tasks example, that demonstrates recovery/retry logic (source code).
First, I'm not quite sure whether my case is suitable to use spring state machine.
Here're my case:
I have a big mutable object and a set of logic unit which will manipulate this mutable object in a certain sequence.
For a normal flow: A.exec -> B.exec -> C.exec -> Done
For a bad flow that exception throws from A: A -> Error - > Done (B and C is bypassed)
For a bad flow that exception throws from B: A -> B - > Another Flow
I guess A, B, C could be modeled as a state while an action could be used to perform real biz logic when transit from A to B.
How can I capture possible thrown exception from A and change the target to another state instead of B?
Thanks
Leon
I'd use junction or choice and define guards for outgoing transitions. Something what is discussed in gh240. Then you can catch your exceptions and i.e. store something in an extended state and then from your guards you are free to evaluate different conditions.
Choice is pretty much if/elseif/else structure to define which branch machine will follow for transitions.
There's also deploy sample which is modelled with same concepts.
(
SynthDef(\testEvt,{
arg out, gate = 1;
var sint = Blip.ar(440) * Linen.kr(gate,doneAction:2,releaseTime:0.8);
Out.ar(out, Pan2.ar(sint, 0));
}).add();
Synth(\testEvt)
(instrument: \testEvt, freq:220, sustain: inf).play;
(instrument: \testEvt,freq:220).play;
)
Executing the first and the second line after the SynthDef would create a synth which playes forever, whereas the third line's synth plays for 0.8 seconds as per default value the generated event.
The problem is that I don't use 'sustain' anywhere in my SynthDef and it uses automatically just because there is a Linen.
The same this doesn't happen for freq: both the events play at 440 and not at 220, and that's just because the SynthDef doesn't use 'freq' as an argument. So why sustain doesn't follow the same rule ?
Also, is there a way to reference synths created by an event ? So that, when they have sustain: inf as argument, I can free them on a later time.
(instrument: \testEvt, freq:220, sustain: inf).play;
and
(instrument: \testEvt,freq:220).play;
are events. Events handle a lot of things for you. One thing they do is calculate when to set a gate to 0. (Remember that gate is one of the arguments in your SynthDef.) In the first example, because you sustain for infinite duration, the gate never goes to zero. In the second example, it uses the default duration and sets the gate to zero after that duration has passed. You can find out what key words are used in event environment variables by looking at the Event.sc source file. If you search for sustain, you'll find out the other keywords it uses for timing. One of these is dur. Try this:
(instrument: \testEvt, dur:3).play
Freq is also a keyword for events, but since you have no freq argument, it can't effect your synthDef. If you want to set the freq, you'll need to make a change:
SynthDef(\testEvt,{
arg out, gate = 1, freq = 440;
var sint = Blip.ar(freq) * Linen.kr(gate,doneAction:2,releaseTime:0.8);
Out.ar(out, Pan2.ar(sint, 0));
}).add();
For contrast between events and controlling a synth directly, try:
a = Synth.new(\testEvt, [\out, 0, \gate, 1])
You can add in any other arguments you want, like freq or sustain, but they have no effect because those aren't arguments to your synthdef. And, unlike Event, synth doesn't do any calculations on your behalf. When you want the note to end, set the gate to 0 yourself:
a.set(\gate, 0)
It's good to be aware of event environment variables because they're also used by Pbinds and by using them, you can effect other things. If you had a synthdef that used sustain as an argument for something else, you could be surprised by it changing your durations.
Regarding your last sub-question,
Also, is there a way to reference synths created by an event ? So that, when they have sustain: inf as argument, I can free them on a later time.
Yes, by "indexing" the Event by \id key. This actually returns an array of node ids because an Event with \strum can fire up more than one node/synth. Also, the \id value is nil while the event is not playing. But this indexing method is fairly unnecessary for what you want, because...
You can end the (associated) synth by ending the Event early with release, just like for the Synth itself. What this does is basically gate-out its internal synth. (In your example, this release call transitions to the release point of the ASR envelope generated by Linen, by lowering gate to 0.). And, of course, use a variable to save the "reference" to the synth and/or event, if don't plan to release it right away in a program (which would produce no sound with a gated envelope).
Basically
fork { var x = Synth(\testEvt); 2.wait; x.release }
does the same as
fork { var e = (instrument: \testEvt, sustain: inf).play; 2.wait; e.release }
except there's one layer of indirection in the latter case for the release. The first example is also equivalent to
fork { var x = Synth(\testEvt); 2.wait; x.set(\gate, 0); }
which does the work of release explicitly. Event also supports set and it passes the value to the corresponding Synth control (if the latter was properly added on the server.)
Now the complicated method you asked about (retrieving node ids for the event and sending them messages) is possible too... although hardly necessary:
fork { var e = (instrument: \testEvt, sustain: inf).play; 2.wait;
e[\id].do({ arg n; s.sendMsg("/n_set", n, "gate", 0); }) }
By the way, you can't use wait outside of a Routine, that's why fork was needed in the above examples. Interactively, in the editor, you can "wait manually", of course, before calling release on either the Synth or the Event.
As a somewhat subtle point of how envelope gating works, it doesn't actually start playing (technically begin transitioning to the endpoint of the first [attack] envelope segment) until you set gate to 1. I.e. you can delay the (envelope) start as in:
fork { x = Synth(\testEvt, [\gate, 0]); 3.wait; x.set(\gate, 1); 2.wait; x.release }
Beware that the default Event.play doesn't generate this 0 to 1 gate transition though, i.e. you can't rely on it to fire your synth's envelope if you set the initial gate value to zero in your SynthDef.
Also, I'm assuming that by "free" you mean "stop playing" rather than "free their memory on the server". There's no need to manually free those (event) synths in the latter sense since they have doneAction:2 in the envelope, which does that for you once they are released and the final segment of the envelope finishes playing. If you somehow want to kill the synth right away (like Ctrl+. does) instead of triggering its fade-out you can replace the message sent in the inner function of the "complicated" example (above) with s.sendMsg("/n_free", n). Or much more simply
fork { var e = (instrument: \testEvt, sustain: inf).play; 2.wait; e.free }
Also, if you wonder about \strum, an example is:
e = (instrument: \testEvt, sustain: inf, strum: 1, out: #[0, 0]).play
Now e[\id] is an array of two nodes. Event is a bit cheeky in that it will only create multiple nodes for arrays passed to actual Synth controls rather than random fields, so "strumming" \freq (or its precursors like \degree etc.) only creates multiple nodes if your SynthDesc has a freq control.
Alas the "complicated" method is almost useless when it comes to playing Pbinds (patterns). This is because Pbind.play returns and EventStreamPlayer... that alas makes a private copy of the prototype event being played and plays that private copy, which is inaccessible to the caller context (unless you hack EventStreamPlayer.prNext). Confusingly EventStreamPlayer has an accessible event variable, but that's only the "prototype", not the private copy event being played... So if p is an instance of an EventStreamPlayer then p.event[\id] is always nil (or whatever you set it to beforehand) even while playing. Since one seldom plays Events individually and much more often patterns...
Simply as a hacking exercise tough, it turns out there is an even more convoluted way to access the ids of nodes that EventStreamPlayer fires... This relies on overriding the default Event play which thankfully can be extended outside class inheritance because the default is conveniently saved in a class dictionary...
(p = Pbind(\instrument, \testEvt, \sustain, Pseq([1, 2]), \play, {
arg tempo, srv;
var rv;
"playhack".postln;
rv = Event.parentEvents[\default][\play].value(tempo, srv);
~id.postln;
rv;
}).play)
In general however, patterns are clearly not designed to be used this way, i.e. by hacking "a layer below" to get to the node ids. As "proof", while the above works well enough with Pbind (which uses the default Event type \note) it doesn't work reliably with Pmono which doesn't set the Event \id on its first note (Event type \monoNote) but only on subsequent notes (which generate a different Event type, \monoSet). Pmono keeps an internal copy of the node id, but this is completely inaccessible on the first mono note; it only copies it to the Events on the subsequent notes for some reason (bug perhaps, but could be "by design"). Also, if you use Pdef which extends Event with type \phrase... the above hack doesn't work all, i.e. \id is never set by type \phrase; perhaps you can get to the underlying sub-events generated somehow... I haven't bothered to investigate further.
The SC documentation (in the pattern guide) even says at one point
Remember that streams made from patterns don't expose their internals. That means you can't adjust the parameters of an effect synth directly, because you have no way to find out what its node ID is.
That's not entirely correct given the above hack, but it is true in some contexts.
I have a state machine for my npcs that is structured like the following,
execute state
[[[pred1 pred2....] state1]
[[pred3 pred4....] state2]
[[pred5 pred6....] staten]]
What happens is after current state completes, it starts iterating through the states/predicates list and as soon as a list of predicates that returns all true it will jump to the state that it is associated with.
Certain events can happen during all states, say player commands npc to go somewhere. Just like any other state transition I can check for a predicate and change state but adding the same piece of code to every state seems a bit lame. So I was wondering how people deal with events in state machines?
Just make a data structure like:
state1 -> event1, event2
state2 -> event1
state3 -> event2, event3
By the way, what you have outlined doesn't look like a state machine. In state machine, next state depends on the previous one, so it would look like:
[state1, condition1] -> state2
[state1, condition2] -> state3
...
(condition is your set of predicates). You must also somehow assure that the transition is unique, i.e. that condition1 and condition2 cannot be fulfilled at the same time. Or take the first one which is true.
Try to use pattern called "State" - http://en.wikipedia.org/wiki/State_pattern
Define abstract superclass (e.g. class AbsatractState, put there code of methods that common for all states), and all classes that represents real states must been subclassed from it.
When you have a particular action that can be undertaken from all possible states, do as you would do in mathematics : factor it!
i.e : 4*10 + 5*10 + 6*10 + 4*20 + 5*20 + 6*20 = (4+5+6)*(10+20)
i.e : your (oblivion) npc can be sleeping, or at work, or eating. In all three cases, it must react to some events (be talked to, be attacked, ...). Build two FSM : Daily activity = [sleep, work, eat]. Reaction state : {Undisturbed, Talked to, Attacked, ...}. Then forward the events only to the second FSM
And you can keep on factoring FSM, as long as you're factoring independant things. For example, the mood of the npc (happy, neutral, angry, ...) is independant from it's daily activity and its reaction state. I mean "independant" in the sense "the npc can be at work, talked to, and angry, and there's no contradiction". Of course FSM influence each other, npc that are attacked tend to be angry.
So you could add a third FSM for the Mood state, instead of incorporating it in every single node
Use a hierarchical state machine (HSM). HSMs are exactly designed to factor out the common behavior into superstates and make it reusable for all substates. To learn more about HSMs, you can start with the Wikipedia article "UML State Machine" at http://en.wikipedia.org/wiki/UML_state_machine.