113 lines · 4.0 KB · TypeScript
RawDownload
import { Cause, Effect, Exit, Fiber, Schema } from "effect";import { startComputeSupervisor } from "./modules/compute/supervisor";import { AppContextService, getModelsDirectoryState, type AppContext } from "./app-context";import { createControllerRuntime, type ControllerRuntime } from "./core/effect-runtime";import { parseBooleanFlag } from "./core/validation";import { createApp } from "./http/app";import { startMetricsCollector } from "./modules/system/metrics-collector";import { detectGpuMonitoringTool } from "./modules/system/platform/gpu"; class ControllerStartupError extends Schema.TaggedErrorClass<ControllerStartupError>()(  "ControllerStartupError",  { operation: Schema.String, message: Schema.String, source: Schema.Unknown },) {} const startupError = (operation: string, source: unknown): ControllerStartupError =>  new ControllerStartupError({ operation, message: String(source), source }); const metricsDisabled = (): boolean =>  parseBooleanFlag(process.env["LOCAL_STUDIO_DISABLE_METRICS"]); const logBootSummary = (context: AppContext, port: number): Effect.Effect<void> =>  detectGpuMonitoringTool().pipe(    Effect.tap((gpuTool) =>      Effect.sync(() => {        const { config } = context;        const directoryState = getModelsDirectoryState();        const authMode = config.api_key ? "api-key" : "unauthenticated (no LOCAL_STUDIO_API_KEY)";        context.logger.info(          [            "Boot summary:",            `listen=${config.host}:${port}`,            `data_dir=${config.data_dir}`,            `db_path=${config.db_path}`,            `models_dir=${config.models_dir} (${directoryState === "missing" ? "MISSING" : directoryState})`,            `auth=${authMode}`,            `gpu_tool=${gpuTool ?? "none detected"}`,          ].join(" "),        );      }),    ),    Effect.asVoid,  ); const serve = (  context: AppContext,  runtime: ControllerRuntime,): Effect.Effect<ReturnType<typeof Bun.serve>, ControllerStartupError> =>  Effect.try({    try: () => {      const app = createApp(context, runtime);      return Bun.serve({        port: context.config.port,        hostname: context.config.host,        fetch: app.fetch,        idleTimeout: 120,      });    },    catch: (source) => startupError("server.start", source),  }); const runtime = createControllerRuntime();const program = Effect.scoped(  Effect.gen(function* () {    const context = yield* AppContextService;    if (metricsDisabled()) {      context.logger.warn("Metrics collector disabled by LOCAL_STUDIO_DISABLE_METRICS");    } else {      yield* Effect.forkScoped(startMetricsCollector(context));    }    {      yield* Effect.forkScoped(        startComputeSupervisor(context.compute.service, (error) =>          context.logger.error("Compute supervisor error", { error: String(error) }),        ),      );    }    const server = yield* Effect.acquireRelease(serve(context, runtime), (resource) =>      Effect.tryPromise({        try: () => resource.stop(),        catch: (source) => startupError("server.stop", source),      }).pipe(        Effect.catch((error) =>          Effect.sync(() =>            context.logger.error("Server failed to stop", { error: String(error) }),          ),        ),      ),    );    context.logger.info(`Controller listening on ${context.config.host}:${server.port}`);    yield* logBootSummary(context, server.port ?? context.config.port);    return yield* Effect.never;  }),);const fiber = runtime.runFork(program);let shuttingDown = false; fiber.addObserver((exit) => {  if (shuttingDown || Exit.isSuccess(exit)) return;  shuttingDown = true;  console.error(Cause.pretty(exit.cause));  void runtime.dispose().finally(() => process.exit(1));}); const shutdown = (): void => {  if (shuttingDown) return;  shuttingDown = true;  void Effect.runPromise(    Fiber.interrupt(fiber).pipe(Effect.andThen(runtime.disposeEffect)),  ).finally(() => process.exit(0));}; process.on("SIGINT", shutdown);process.on("SIGTERM", shutdown);