sonntam / node-red-contrib-xstate-machine

A xstate-based state machine implementation using state-machine-cat visualization for node red.
MIT License
22 stars 8 forks source link

Warning: No implementation found for activity #27

Closed wpmccormick closed 3 years ago

wpmccormick commented 3 years ago

I have a flow that was started from the default flow in the smxstate node. I added more states and actions, an renamed the dostuff activity, but now I can't get the activity implementation to be found. All I see in the console log is the Warning that is the subject of this issue.

Is there some way I can get more verbose logging? Or some way to trace into what exactly is (not) happening in my machine config?

If the implementation is not found, how is it that the flow able to be deployed?

Here's the complete payload from the top output when transitioning to the state with the activity:

{"state":{"enabled":{"ticket":{"call":"running"}}},"changed":true,"done":false,"activities":{"check":{"type":"xstate.start","activity":{"type":"check"}}},"actions":[{"type":"xstate.start","activity":{"type":"check"}},{"type":"xstate.send","event":{"type":"xstate.after(30000)#c5791bba.c55e88.enabled.ticket.call.running"},"delay":30000,"id":"xstate.after(30000)#c5791bba.c55e88.enabled.ticket.call.running","_event":{"name":"xstate.after(30000)#c5791bba.c55e88.enabled.ticket.call.running","data":{"type":"xstate.after(30000)#c5791bba.c55e88.enabled.ticket.call.running"},"$$type":"scxml","type":"external"}}],"event":{"type":"RUNNING","payload":1628623713161},"context":{"startLevel":0,"stopLevel":0,"runTime":0}}

Here's the flow:

const { assign } = xstate;

/**
 * Guards
 */
const maxRunTimeElapsed = (context, event) => {
  return context.runTime >= maxRunTime;
};

/**
 * Actions
 */
const ticketSend = (context, event) => {
    node.send({ payload: "Ticket Complete" });
    console.log('ticket complete time:', Date.now());
};

const incrementCounter = assign({
  counter: (context, event) => context.counter + 1
});

const pumpStop = (context, event) => {
    node.send({ payload: "Pump Stop" });
    console.log('pump stop time:', Date.now());
};

const pumpStart = (context, event) => {
    node.send({ payload: "Pump Start" });
    console.log('pump start time:', Date.now());
};

const ticketStateSet = (context, event) => {
    node.send({ payload: "Set Ticket State" });
    console.log('set ticket state time:', Date.now());
};

/**
 * Activities
 */
 //See https://xstate.js.org/docs/guides/activities.html
const check = () => {
    const interval = setInterval(() => {
        node.send({ payload: 'Check Level' });
        }, 2000);
    return () => clearInterval(interval);
};

const doStuff = () => {
  // See https://xstate.js.org/docs/guides/activities.html
  const interval = setInterval(() => {
    node.send({ payload: 'BEEP' });
  }, 1000);
  return () => clearInterval(interval);
};

return {
  machine: {

    // Local context for entire machine
    context: {
      startLevel: 0,
      stopLevel: 0,
      dispenseQty: global.get('dispenseQty'),
      runTime: 0,
      maxRunTime: global.get('startLevel')
    },

    // Initial state
    initial: 'off',

    // State definitions
    states: {
      off: {
        /* Platform secret switch is open */
        on: {
          ENABLE: 'enabled'
        }
      },
      enabled: {
        /* Platform secret switch is closed */
        //type: 'compound',
        initial: 'idle',
        on: {
            DISABLE: 'off'
        },
        states: {
          idle: {
              on: {
                TICKET: 'ticket'  
              }
          },
          ticket: {
            //type: 'compound',
            initial: 'idle',
            onDone: 'idle',
            states: {
              idle: {
                entry: ticketStateSet,
                on: {
                  CALL: 'call',
                  COMPLETE: 'complete'
                }
              },
              call: {
                //type: 'compound',
                initial: 'starting',
                entry: ticketStateSet,
                onDone: 'complete',
                states: {
                  starting: {
                    entry: pumpStart,
                    on: {
                      RUNNING: 'running'
                    }
                  },
                  running: {
                    on: {
                      STOP: 'stopping',
                      STOPPED: 'stopped'
                    },
                    after: {
                      30000: { target: 'stopping' }
                    },
                    activities: check
                  },
                  stopping: {
                    entry: pumpStop,
                    on: {
                      STOPPED: 'stopped'
                    }
                  },
                  stopped: {
                    type: 'final'
                  }
                }
              },
              complete: {
                type: 'final',
                entry: [ticketSend, ticketStateSet]

              }
            }
          }
        }
      }
    },
    config: {
      activities: {check},
      actions: {
        ticketSend,
        pumpStart,
        pumpStop,
        ticketStateSet
      },
      guards: {
        maxRunTimeElapsed
      }

      //delays: {
      //  /* ... */
      //},
      //services: {
        /* ... */
      //}
    }
  }
};
wpmccormick commented 3 years ago

Sorry, I figured it out. My config section was off by one closing }.