0

I have an external function called onMessageUpdated

I need to send events from that function to a child state machine.

Here's how I'm binding that function already in invoked service:

states: {
createThread: {
    invoke: {
      src: "createThread",
      onDone: {
        target: "threadCreated",
        actions: assign({
          threadName: (context, event) => event.data.threadId,
          boundOnMessageUpdated: (context: any, event: any) =>
            event.data.boundOnMessageUpdated,
        }),
      },
      onError: {
        target: "error",
        actions: assign({
          error: (context, event) => event.data,
        }),
      },
    },
  },
}

services: {
  createThread: async (context, event) => {
    const threadId = await createThread(context.threadName);

    return {
      threadId,
      boundOnMessageUpdated: onMessageUpdated.bind(
        null,
        threadId
      ),
    };
  },
}

This machine is spawned from a parent machine. How do send an event from onMessageUpdated? Tried a couple ways:

export const onMessageUpdated = (
    threadId: string,
    oldMessage: Message<boolean> | PartialMessage,
    newMessage: Message<boolean> | PartialMessage
  ) => {
    if (newMessage.channel.id === threadId && newMessage.content) {
      logger.debug('Sending "UPDATED_MESSAGE" event to "messageSequence"');
      // send({
      //   type: "UPDATED_MESSAGE",
      //   payload: {
      //     content: newMessage.content,
      //   },
      // });
      raise<unknown, GenerateMachineEvent>({
        type: "UPDATED_MESSAGE",
        payload: { content: newMessage.content },
      });
      // sendTo()
      // sendTo("messageSequence", {
      // type: "UPDATED_MESSAGE",
      // });
    }
  };
Gezim
  • 7,112
  • 10
  • 62
  • 98

1 Answers1

0

You could invoke a callback rather than a promise. This type of invocation provides you with a callback function allowing you to send events back to the machine.

I think the real problem here though is how you have modeled your machine. Having to store non-serializable data like a function in context state is often a sign that things can be done a better way.

What if createThread resolved with the just the thread id and you stored that on context state?

Statemachine that creates a thread and uses it in an invoked callback

{
  "id": "New Machine",
  "context": {
    "threadId": "null"
  },
  "initial": "createThread",
  "states": {
    "createThread": {
      "invoke": {
        "src": "createThread",
        "id": "createThread",
        "onDone": [
          {
            "target": "threadCreated",
            "actions": assign({threadId: 1234})
          }
        ],
        "onError": [
          {
            "actions": assign({error: event.data})
          }
        ]
      }
    },
    "threadCreated": {
      "invoke": {
        "src": "onMessageUpdated",
        "id": "onMessageUpdated"
      }
    }
  }
}
chautelly
  • 447
  • 3
  • 14
  • Thanks so much for this. I need a reference to those function as their handlers and in a final state I want to stop listening to those events which are bound to this listeners. Does that make sense at all? – Gezim Apr 22 '23 at 04:35
  • I would need some context on where/when you are calling `boundOnMessageUpdated`. – chautelly Apr 22 '23 at 19:25