From 75f3e827c3c2bcc019837414ad97b39e6b17600c Mon Sep 17 00:00:00 2001 From: Jethro Muller Date: Mon, 12 Dec 2022 15:21:11 +0200 Subject: [PATCH 1/3] Allow initialStateFunc to be a promise - wait for init before processing messages --- @nact/core/actor.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/@nact/core/actor.ts b/@nact/core/actor.ts index c2a82ce..8340827 100644 --- a/@nact/core/actor.ts +++ b/@nact/core/actor.ts @@ -56,7 +56,8 @@ export class Actor | ((msg: any, err: any, ctx: any, child?: undefined | LocalActorRef) => any); initialState: State | undefined; - initialStateFunc: ((ctx: ActorContext) => State) | undefined; + initialStateFunc: ((ctx: ActorContext) => State | Promise) | undefined; + initializeStatePromise: Promise shutdownPeriod?: Milliseconds; state: any; timeout?: Milliseconds; @@ -101,16 +102,20 @@ export class Actor x.stop()); - this.initializeState(); + this.initializeStatePromise = this.initializeState(); this.resume(); } @@ -287,6 +292,7 @@ export class Actor { try { + await this.waitUntilInitialized(); let ctx = this.createContext(); let next = await Promise.resolve(this.f.call(ctx, this.state, message, ctx)); this.state = next; @@ -350,7 +356,7 @@ export type ActorProps, initialState?: State, - initialStateFunc?: (ctx: ActorContext) => State, + initialStateFunc?: (ctx: ActorContext) => State | Promise, afterStop?: (state: State, ctx: ActorContext) => void | Promise }; From 514a05d400bd09c3c9e758d4dae7bdec973dda52 Mon Sep 17 00:00:00 2001 From: Jethro Muller Date: Mon, 12 Dec 2022 15:30:09 +0200 Subject: [PATCH 2/3] Add async initialStateFunc test --- @nact/core/actor.test.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/@nact/core/actor.test.ts b/@nact/core/actor.test.ts index ed18cb4..de36e13 100644 --- a/@nact/core/actor.test.ts +++ b/@nact/core/actor.test.ts @@ -164,6 +164,31 @@ describe('Actor', function () { handled.should.be.true; }); + it('correctly handles an asynchronous initial state function', async function () { + let actor = spawn( + system, + function (state, msg) { + if (msg.type === 'query') { + dispatch(msg.sender, state); + return state; + } else if (msg.type === 'append') { + return state + msg.payload; + } + }, + { + name: 'Nact', + initialStateFunc: async () => { + await new Promise(f => setTimeout(f, 20)); + return 'Cheese!'; + }, + } + ); + + dispatch(actor, { payload: ' Magical wheels of golden hue!', type: 'append' }); + let result = await query(actor, x => ({ type: 'query', sender: x }), 30); + result.should.equal('Cheese! Magical wheels of golden hue!'); + }); + it('evalutes in order when returning a promise from a stateful actor function', async function () { let child = spawn( system, From 5f9f9a112814305690dcec02c4502d63da8bd8a2 Mon Sep 17 00:00:00 2001 From: Jethro Muller Date: Mon, 12 Dec 2022 15:41:19 +0200 Subject: [PATCH 3/3] Add async initialStateFunc test with error --- @nact/core/actor.test.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/@nact/core/actor.test.ts b/@nact/core/actor.test.ts index de36e13..b5463b2 100644 --- a/@nact/core/actor.test.ts +++ b/@nact/core/actor.test.ts @@ -189,6 +189,31 @@ describe('Actor', function () { result.should.equal('Cheese! Magical wheels of golden hue!'); }); + it('correctly handles an async initial state function which throws an error', async function () { + let handled = false; + let actor = spawn( + system, + function (state, msg) { + if (msg.type === 'query') { + dispatch(msg.sender, state); + return state; + } else if (msg.type === 'append') { + return state + msg.payload; + } + }, + { + name: 'Nact', + initialStateFunc: async () => { + await new Promise(f => setTimeout(f, 15)); + throw new Error('A bad moon is on the rise'); + }, + onCrash: (_: any, __: any, ctx: { stop: any; }) => { handled = true; return ctx.stop; } + } + ); + await retry(() => isStopped(actor).should.be.true, 12, 10); + handled.should.be.true; + }); + it('evalutes in order when returning a promise from a stateful actor function', async function () { let child = spawn( system,