fix: app lifecycle shutdown

This commit is contained in:
Nicolas Meienberger 2026-03-31 17:53:10 +02:00
parent e459606436
commit 7d61e7d465
4 changed files with 16 additions and 18 deletions

View file

@ -1,8 +1,8 @@
import { afterEach, describe, expect, mock, spyOn, test } from "bun:test"; import { afterEach, describe, expect, mock, spyOn, test } from "bun:test";
import { Scheduler } from "../../../core/scheduler"; import { Scheduler } from "../../../core/scheduler";
import * as agentsManagerModule from "../../agents/agents-manager";
import * as backendModule from "../../backends/backend"; import * as backendModule from "../../backends/backend";
import type { VolumeBackend } from "../../backends/backend"; import type { VolumeBackend } from "../../backends/backend";
import * as bootstrapModule from "../bootstrap";
import { createTestVolume } from "~/test/helpers/volume"; import { createTestVolume } from "~/test/helpers/volume";
const loadShutdownModule = async () => { const loadShutdownModule = async () => {
@ -21,7 +21,7 @@ describe("shutdown", () => {
const stopScheduler = mock(async () => { const stopScheduler = mock(async () => {
events.push("scheduler.stop"); events.push("scheduler.stop");
}); });
const stopAgentRuntime = mock(async () => { const stopApplicationRuntime = mock(async () => {
events.push("agents.stop"); events.push("agents.stop");
}); });
const unmountVolume = mock(async () => { const unmountVolume = mock(async () => {
@ -39,7 +39,7 @@ describe("shutdown", () => {
}); });
spyOn(Scheduler, "stop").mockImplementation(stopScheduler); spyOn(Scheduler, "stop").mockImplementation(stopScheduler);
spyOn(agentsManagerModule, "stopAgentRuntime").mockImplementation(stopAgentRuntime); spyOn(bootstrapModule, "stopApplicationRuntime").mockImplementation(stopApplicationRuntime);
spyOn(backendModule, "createVolumeBackend").mockImplementation( spyOn(backendModule, "createVolumeBackend").mockImplementation(
() => () =>
({ ({

View file

@ -1,5 +1,5 @@
import { runDbMigrations } from "../../db/db"; import { runDbMigrations } from "../../db/db";
import { agentManager, spawnLocalAgent } from "../agents/agents-manager"; import { agentManager, spawnLocalAgent, stopAgentRuntime } from "../agents/agents-manager";
import { runMigrations } from "./migrations"; import { runMigrations } from "./migrations";
import { startup } from "./startup"; import { startup } from "./startup";
@ -25,3 +25,11 @@ export const bootstrapApplication = async () => {
throw err; throw err;
} }
}; };
export const stopApplicationRuntime = async () => {
try {
await stopAgentRuntime();
} finally {
bootstrapPromise = undefined;
}
};

View file

@ -2,11 +2,11 @@ import { Scheduler } from "../../core/scheduler";
import { db } from "../../db/db"; import { db } from "../../db/db";
import { logger } from "@zerobyte/core/node"; import { logger } from "@zerobyte/core/node";
import { createVolumeBackend } from "../backends/backend"; import { createVolumeBackend } from "../backends/backend";
import { stopAgentRuntime } from "../agents/agents-manager"; import { stopApplicationRuntime } from "./bootstrap";
export const shutdown = async () => { export const shutdown = async () => {
await Scheduler.stop(); await Scheduler.stop();
await stopAgentRuntime(); await stopApplicationRuntime();
const volumes = await db.query.volumesTable.findMany({ const volumes = await db.query.volumesTable.findMany({
where: { status: "mounted" }, where: { status: "mounted" },

View file

@ -1,20 +1,10 @@
import { definePlugin } from "nitro"; import { definePlugin } from "nitro";
import { bootstrapApplication } from "../modules/lifecycle/bootstrap"; import { bootstrapApplication, stopApplicationRuntime } from "../modules/lifecycle/bootstrap";
import { logger } from "@zerobyte/core/node"; import { logger } from "@zerobyte/core/node";
import { toMessage } from "../utils/errors"; import { toMessage } from "../utils/errors";
import { stopAgentRuntime } from "../modules/agents/agents-manager";
type ProcessWithAgentCloseHook = NodeJS.Process & {
__zerobyteAgentRuntimeCloseHookRegistered?: boolean;
};
export default definePlugin(async (nitroApp) => { export default definePlugin(async (nitroApp) => {
const runtimeProcess = process as ProcessWithAgentCloseHook; nitroApp.hooks.hook("close", stopApplicationRuntime);
if (!runtimeProcess.__zerobyteAgentRuntimeCloseHookRegistered) {
nitroApp.hooks.hook("close", stopAgentRuntime);
runtimeProcess.__zerobyteAgentRuntimeCloseHookRegistered = true;
}
await bootstrapApplication().catch((err) => { await bootstrapApplication().catch((err) => {
logger.error(`Bootstrap failed: ${toMessage(err)}`); logger.error(`Bootstrap failed: ${toMessage(err)}`);