Start the controller and host CLIs faster

Like ctl, the controller and host now compile schema validators on first
use instead of at import, which cost about 120 ms per invocation. The
Controller and Host classes are only imported by the commands that
start them, so config, bootstrap and the other commands no longer load
express, ws and the rest of the servers. clusteriocontroller config set
goes from 413 ms to 231 ms and clusteriohost config set from 412 ms to
225 ms.

The integration tests run the bins, like npx does, instead of the
package directories.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bbassieandClaude Opus 5.5 committed 2026-10-30 17:29:42 +00:00
1 parent a174c355d2
commit 0312a3b099
5 files changed
+20 -5

No files matched your search

+6 -1
View File
@@ -26,10 +26,12 @@ import DailyRotateFile from "winston-daily-rotate-file";
import jwt from "jsonwebtoken";
// homebrew modules
// Reduce startup time by lazy compiling schemas.
import "./src/set_lazy_schema_compilation.js";
import * as lib from "@clusterio/lib";
import { ConsoleTransport, levels, logger } from "@clusterio/lib";
import Controller from "./src/Controller.js";
import type Controller from "./src/Controller.js";
import UserManager from "./src/UserManager.js";
import UserRecord from "./src/UserRecord.js";
import packageConfig from "@clusterio/controller/package.json" with { type: "json" };
@@ -203,6 +205,7 @@ async function handleBootstrapCommand(
}
let ctlConfig = new lib.CtlConfig("control");
const { default: Controller } = await import("./src/Controller.js");
ctlConfig.set("ctl.controller_url", Controller.calculateControllerUrl(controllerConfig));
ctlConfig.set(
"ctl.controller_token",
@@ -475,6 +478,8 @@ async function startup() {
return;
}
// Loaded here as the server is not needed by the other commands
const { default: Controller } = await import("./src/Controller.js");
controller = await Controller.fromConfig(
controllerConfig,
pluginInfos,
@@ -0,0 +1,3 @@
// This needs to be a separate file due to ECMAScript Modules evaluating code in
// imported modules before any code in the file that imports it.
(global as any).lazySchemaCompilation = true;
+5 -1
View File
@@ -20,10 +20,12 @@ import winston from "winston";
import "winston-daily-rotate-file";
// internal libraries
// Reduce startup time by lazy compiling schemas.
import "./src/set_lazy_schema_compilation.js";
import * as lib from "@clusterio/lib";
import { ConsoleTransport, levels, logger } from "@clusterio/lib";
import Host from "./src/Host.js";
import type Host from "./src/Host.js";
import { createScenarioCommand, handleCreateScenarioCommand } from "./src/create_scenario.js";
let host: Host | undefined;
@@ -233,6 +235,8 @@ async function startHost() {
return;
}
// Loaded here as the server is not needed by the other commands
const { default: Host } = await import("./src/Host.js");
let hostConnector = new HostConnector(hostConfig, pluginInfos);
host = await Host.fromConfig(
hostConfig,
@@ -0,0 +1,3 @@
// This needs to be a separate file due to ECMAScript Modules evaluating code in
// imported modules before any code in the file that imports it.
(global as any).lazySchemaCompilation = true;
+3 -3
View File
@@ -205,17 +205,17 @@ export function exec(command, options = {}) {
}
export function execController(...args) {
args[0] = `node --enable-source-maps ../../packages/controller ${args[0]}`;
args[0] = `node --enable-source-maps ../../packages/controller/dist/node/controller.js ${args[0]}`;
return exec(...args);
}
export function execHost(...args) {
args[0] = `node --enable-source-maps ../../packages/host ${args[0]}`;
args[0] = `node --enable-source-maps ../../packages/host/dist/node/host.js ${args[0]}`;
return exec(...args);
}
export function execCtlProcess(...args) {
args[0] = `node --enable-source-maps ../../packages/ctl ${args[0]}`;
args[0] = `node --enable-source-maps ../../packages/ctl/dist/node/ctl.js ${args[0]}`;
return exec(...args);
}