untu / comedy

Node.js actor framework.
Eclipse Public License 1.0
653 stars 36 forks source link

State of an actor passed into a forked actor does not get updated. #56

Open pct-cclausen opened 3 years ago

pct-cclausen commented 3 years ago
  1. Create a local in-memory actor L
  2. Pass it to a forked actor F
  3. Destroy the local in-memory actor L
  4. The forked actor won't recognize the new state of actor L.

Example:

    const rt = await system.rootActor();
    // local actor L
    const localPrinter = await rt.createChild({
        pipe(data: any) {
            console.log("I got data piped!", data);
        }
    });

    // forked actor F
    const forkedActor = await rt.createChild("/dist/src/dbg", {
        mode: "forked"
    });
    /**
        giveRef(ref: ActorRef) {
        setInterval(() => {
            console.log("The actor state of my ref is: " + ref.getState());
            if (ref.getState() === "ready") {
                ref.send("pipe", Date.now());
            }
        }, 1000);
    }
     */
    forkedActor.send("giveRef", localPrinter);

    /**
     * Prints:
     * The actor state of my ref is: ready
        I got data piped! 1607799890757
        The actor state of my ref is: ready
        I got data piped! 1607799891754
        The actor state of my ref is: ready
        I got data piped! 1607799892754
        The actor state of my ref is: ready
        I got data piped! 1607799893755
        The actor state of my ref is: ready
     */
    await new Promise<void>(resolve => {
        setTimeout(() => {
            resolve();
        }, 5000);
    });

    // destroy local actor
    await localPrinter.destroy();

    // now the prints continue:
    /**
The actor state of my ref is: ready
Sat Dec 12 2020 20:04:55 GMT+0100 (Central European Standard Time) - warn: ForkedActor(5fd51451843499b4f6d3a668): No pending promise for "actor-response": 
{
  type: 'actor-response',
  id: 6,
  body: {
    error: 'destroy() has been called for this actor, no further interaction possible'
  },
  actorId: '5fd51451843499b4f6d3a668'
}
     */
    await new Promise<void>(resolve => {
        setTimeout(() => {
            resolve();
        }, 5000);
    });

It should probably not return "ready" for getState() on ref in the forked actor, after the referenced actor has been destroyed. If I use sendAndReceive("pipe", ...) instead of just send, that one throws an exception saying the actor has been destroyed, but the state of the actor in the forked actor still reports "ready". send on the other hand just fails silently and causes those warning prints to show up a lot.