diff --git a/src/conductor/runner/BasicEvaluator.ts b/src/conductor/runner/BasicEvaluator.ts index aa88ac7..7d7ad28 100644 --- a/src/conductor/runner/BasicEvaluator.ts +++ b/src/conductor/runner/BasicEvaluator.ts @@ -1,16 +1,25 @@ import { ConductorInternalError } from "../../common/errors"; +import { RunnerStatus } from "../types"; import type { IEvaluator, IRunnerPlugin } from "./types"; export abstract class BasicEvaluator implements IEvaluator { readonly conductor: IRunnerPlugin; async startEvaluator(entryPoint: string): Promise { - const initialChunk = await this.conductor.requestFile(entryPoint); - if (!initialChunk) throw new ConductorInternalError("Cannot load entrypoint file"); - this.conductor.sendResult(await this.evaluateFile(entryPoint, initialChunk)); - while (true) { - const chunk = await this.conductor.requestChunk(); - this.conductor.sendResult(await this.evaluateChunk(chunk)); + try { + const initialChunk = await this.conductor.requestFile(entryPoint); + if (!initialChunk) throw new ConductorInternalError("Cannot load entrypoint file"); + this.conductor.sendResult(await this.evaluateFile(entryPoint, initialChunk)); + while (true) { + const chunk = await this.conductor.requestChunk(); + this.conductor.sendResult(await this.evaluateChunk(chunk)); + } + // The REPL loop only exits if the conduit is terminated externally. + this.conductor.updateStatus(RunnerStatus.STOPPED, true); + } catch (e) { + // Always notify the host so it can unblock its own REPL loop. + this.conductor.updateStatus(RunnerStatus.ERROR, true); + throw e; } } diff --git a/src/conductor/runner/RunnerPlugin.ts b/src/conductor/runner/RunnerPlugin.ts index 83f74ab..33a1c7a 100644 --- a/src/conductor/runner/RunnerPlugin.ts +++ b/src/conductor/runner/RunnerPlugin.ts @@ -39,8 +39,14 @@ export class RunnerPlugin implements IRunnerPlugin { console.error(`Host expects at least protocol version ${message.data.minVersion}, but we are on version ${Constant.PROTOCOL_VERSION}`); this.__conduit.terminate(); }], - [ServiceMessageType.ENTRY, function entryServiceHandler(this: RunnerPlugin, message: EntryServiceMessage) { - this.__evaluator.startEvaluator(message.data); + [ServiceMessageType.ENTRY, async function entryServiceHandler(this: RunnerPlugin, message: EntryServiceMessage) { + try { + await this.__evaluator.startEvaluator(message.data); + } catch (_e) { + // BasicEvaluator already sends RunnerStatus.ERROR; this is a safety net for + // evaluator subclasses that override startEvaluator without the same guarantee. + this.updateStatus(RunnerStatus.ERROR, true); + } }] ]);