node.jsserverlessxstate

Invoke a service from a "serverless" fsm (Xstate)


I'm using xsate on a Node.JS backend. Here is the current flow :

Here is some pseudo code

const state  = db.fetch(flowId) ?? machine.initialState;
 // Use State.create() to restore state from a plain object
const previousState = State.create<DefaultContext, MyEvent>(stateDefinition);
// Use machine.resolveState() to resolve the state definition to a new State instance relative to the machine
const resolvedState = machine.resolveState(previousState);
const interpreter = interpret(machine).start(resolvedState);
onst newState: State<DefaultContext, MyEvent, any, Typestate<DefaultContext>> = interpreter.send(event);
db.saveState(flowId, newState);

My question is : Is it possible to Invoke a Promise ?

I would like to keep my FSM "alive" if I have pending promises. The goal is to modify the context based on the promise result. Is there some hook I could use ?

Thanks for any advise.


Solution

  • I have the same use case as you. So what I do is add an extra property to context, say waitingAsync. Set it to true on the state entry, and set it to false on done.

    Follow the Invoking Promises example with some modifications:

    // ...
    loading: {
      // set waitingAsync to true
      entry: assign((context) => ({...context, waitingAsync: true})),
      invoke: {
        id: 'getUser',
        src: (context, event) => fetchUser(context.userId),
        onDone: {
          target: 'success',
          actions: [
            assign({ user: (context, event) => event.data })
            // set waitingAsync to false
            assign((context) => ({...context, waitingAsync: false}))
          ]
        },
      }
    },
    // ...
    

    Then you can use the waitFor helper to wait until the promise is done.

    const interpreter = interpret(machine).start();
    interpreter.send(event);
    await waitFor(interpreter, (state) => !state.context.waitingAsync);