Skip to content

Commit ab1b00f

Browse files
authored
fix: register terminating() callback before command exec (#5038)
1 parent e2f0656 commit ab1b00f

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

src/ignitor/ace.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ export class AceProcess {
9393

9494
await this.#configureCallback(app)
9595

96+
/**
97+
* Register terminating callback BEFORE handling the command.
98+
* This ensures the callback is registered even if a staysAlive
99+
* command calls app.terminate() during its execution.
100+
*/
101+
app.terminating(() => {
102+
const mainCommand = kernel.getMainCommand()
103+
if (mainCommand?.staysAlive) {
104+
process.exitCode = mainCommand.exitCode
105+
}
106+
})
107+
96108
/**
97109
* Handle command line args
98110
*/
@@ -106,10 +118,6 @@ export class AceProcess {
106118
if (!mainCommand || !mainCommand.staysAlive) {
107119
process.exitCode = kernel.exitCode
108120
await app.terminate()
109-
} else {
110-
app.terminating(() => {
111-
process.exitCode = mainCommand.exitCode
112-
})
113121
}
114122
}
115123
}

tests/ignitor/ace_process.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,48 @@ test.group('Ignitor | Ace process', (group) => {
258258
assert.equal(ignitor.getApp()?.getState(), 'terminated')
259259
})
260260

261+
test('set process.exitCode when staysAlive command calls app.terminate() during execution', async ({
262+
cleanup,
263+
assert,
264+
}) => {
265+
cleanup(async () => {
266+
process.exitCode = undefined
267+
await ignitor.terminate()
268+
})
269+
270+
const ignitor = new IgnitorFactory()
271+
.merge({
272+
rcFileContents: {
273+
providers: [() => import('../../providers/app_provider.js')],
274+
},
275+
})
276+
.withCoreConfig()
277+
.create(BASE_URL)
278+
279+
class Greet extends BaseCommand {
280+
static commandName: string = 'greet'
281+
static options = {
282+
staysAlive: true,
283+
}
284+
285+
async run() {
286+
this.exitCode = 1
287+
await this.app.terminate()
288+
}
289+
}
290+
291+
await ignitor
292+
.ace()
293+
.configure(async (app) => {
294+
const kernel = await app.container.make('ace')
295+
kernel.addLoader(new ListLoader([Greet]))
296+
})
297+
.handle(['greet'])
298+
299+
assert.equal(process.exitCode, 1)
300+
assert.equal(ignitor.getApp()?.getState(), 'terminated')
301+
})
302+
261303
test('switch app environment to repl when running repl command', async ({ cleanup, assert }) => {
262304
cleanup(async () => {
263305
await ignitor.terminate()

0 commit comments

Comments
 (0)