Looped invoke in scxml event

394 views Asked by At

I have an scxml event with an "invoke" element. This invoke element updates the datamodel elements when the event is called. How can I make this happen periodically? Is it possible to periodically call this invoke for example, every second? Or perhaps to transition to the event every second?

The problem with the latter is that if I put a transition in the finalize section of the invoke, calling itself, it does not seem to call the invoke section more than once.

1

There are 1 answers

9
jbeard4 On BEST ANSWER

I first wanted to provide some background on <invoke>. <invoke> is placed as a child to <state>. It starts a child state machine session on entering the state, and stops the session on exiting the state. Furthermore, if the child session enters a <final> state, then a done.invoke.invokeid event is dispatched on the parent session. You can use this done.invoke.invokeid event in a transition on the parent state, to force the parent state to exit when the child session terminates. Finally, the parent and child states can communicate with each other through <send>. The parent can communicate with the child using <send> with target attribute set to _invoke_invokeid, and the child can communicate with the parent through <send> with target attribute set to _parent.

Now, onto your questions:

This invoke element updates the datamodel elements when the event is called.

I think there may be a problem with the way you have conceptualized this, because the invoked session has its own datamodel (which is to say, its own memory). You can bind the initial datamodel values of the child session using <param>, but you can't really share memory between the parent and child sessions. This means that you can't update the datamodel in the parent session directly in the child session using e.g. <assign> or <script> tags.

The only way for the child session to update the datamodel in the parent session is to communicate with the parent session through passing events (e.g. <send event="update" target="_parent"><param name="dataToUpdate" expr="dataToUpdate"/></send>). The parent then needs to have a <transition> element so that it can process the event sent from the child session, e.g. <transition event="update"><assign location="dataToUpdate" expr="_event.dataToUpdate"/></transition>.

This leads to the question of whether <invoke> is the best, simplest approach to updating the datamodel periodically. It might be simpler to, for example, just put the datamodel update logic inside of a child of <parallel> state. This way, you could use <assign> to update the datamodel directly.

How can I make this happen periodically? Is it possible to periodically call this invoke for example, every second? Or perhaps to transition to the event every second?

To invoke a session periodically, you would enter and exit the state containing the <invoke> element. The following (untested) code would probably work:

<state id=invokeParent">
  <!-- this is some data that you want the child session to update in the parent session -->
  <datamodel>
    <data id="dataToUpdate" />
  </datamodel>
  <onentry>
    <send event="loop" delay="1s"/> <!-- send the 'loop' event every second to loop in invokeParent -->
  </onentry>
  <transition event="loop" target="invokeParent" /> <!-- this transition will exit and re-enter the state, restarting the invoked session -->
  <transition event="done.invoke.myInvoke" target="invokeParent" /> <!-- also loop if the invoked session terminates -->
  <invoke id="myInvoke" type="scxml" src="file:test276sub1.scxml"/> <!-- this is the invoke -->
  <!-- this targetless transition handles the update event sent from the child session to the parent to update the parent's datamodel -->
  <transition event="update">
    <assign location="dataToUpdate" expr="_event.dataToUpdate"/>
  </transition>
</state>

The problem with the latter is that if I put a transition in the finalize section of the invoke, calling itself, it does not seem to call the invoke section more than once.

I don't believe transition is a legal child of finalize. finalize is meant to contain executable content (e.g. script, assign) that allow you to manipulate events sent by the child session before they are processed by the parent session.

See https://www.w3.org/TR/scxml/#finalize