fix(core): Shut the regex engine down on every exit path, document the getter override shape

exitSuccessFully() was the only path that shut the regex engine down;
one-off commands and the engine v2 data plane both exit without it,
so a future engine with real teardown would leak there. Also note
that needsRegexEngine, unlike its sibling needs* flags, must be
overridden as a getter, not a field.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Emilia 2026-10-06 09:46:47 +01:00
parent b3feec3956
commit fbc63468fb
No known key found for this signature in database
GPG Key ID: 837988349B71DD1A
2 changed files with 4 additions and 1 deletions

View File

@ -115,7 +115,8 @@ export abstract class BaseCommand<F = never> {
/**
* Whether to init the regex engine. Defaults to `needsExpressionEngine`: a command
* that evaluates workflow expressions also evaluates a user's regexes. Override only
* where the two genuinely diverge.
* where the two genuinely diverge, and as a getter (`override get needsRegexEngine()`):
* unlike the other `needs*` flags, this one can't be overridden as a field.
*/
get needsRegexEngine(): boolean {
return this.needsExpressionEngine;
@ -612,6 +613,7 @@ export abstract class BaseCommand<F = never> {
async finally(error: Error | undefined) {
if (error?.message) this.logger.error(error.message);
if (inTest || this.constructor.name === 'Start') return;
if (this.needsRegexEngine) this.regexEngineService.shutdown();
if (this.dbConnection.connectionState.connected) {
await sleep(100); // give any in-flight query some time to finish
await this.dbConnection.close();

View File

@ -77,6 +77,7 @@ export class Engine extends BaseCommand {
await this.responseSender?.stop();
}
await Expression.disposeExpressionEngine();
if (this.needsRegexEngine) this.regexEngineService.shutdown();
} catch (error) {
await this.exitWithCrash('There was an error shutting down the engine.', error);
}