@nmakarov/cli-toolkit 0.47.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-runner.cjs +380 -16
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +380 -16
- package/dist/cli-runner.js.map +1 -1
- package/dist/deploy.cjs +59 -15
- package/dist/deploy.cjs.map +1 -1
- package/dist/deploy.js +58 -15
- package/dist/deploy.js.map +1 -1
- package/dist/index.cjs +377 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +367 -32
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +3 -0
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +3 -0
- package/dist/init.js.map +1 -1
- package/dist/tasks.cjs +318 -17
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.js +309 -17
- package/dist/tasks.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5793,10 +5793,9 @@ function buildEcosystemConfig(service, paths) {
|
|
|
5793
5793
|
const outLog = join9(paths.logs, `${pm2.appName}.out.log`);
|
|
5794
5794
|
const errLog = join9(paths.logs, `${pm2.appName}.err.log`);
|
|
5795
5795
|
return `/**
|
|
5796
|
-
* pm2 ecosystem for ${service.name} \u2014
|
|
5797
|
-
*
|
|
5798
|
-
*
|
|
5799
|
-
* Tweak \`args\` here, then: pm2 reload ${paths.ecosystem} --update-env
|
|
5796
|
+
* pm2 ecosystem for ${service.name} \u2014 written by cli-toolkit deploy from the
|
|
5797
|
+
* service manifest (init/deploy). Do not hand-edit; change pm2.* in the
|
|
5798
|
+
* manifest and redeploy. cwd \u2192 \`current\` symlink.
|
|
5800
5799
|
*/
|
|
5801
5800
|
module.exports = {
|
|
5802
5801
|
apps: [
|
|
@@ -5804,7 +5803,7 @@ module.exports = {
|
|
|
5804
5803
|
name: "${pm2.appName}",
|
|
5805
5804
|
script: "${pm2.script}",
|
|
5806
5805
|
cwd: "${paths.current}",
|
|
5807
|
-
args: "${pm2.args}",
|
|
5806
|
+
args: "${pm2.args ?? ""}",
|
|
5808
5807
|
instances: 1,
|
|
5809
5808
|
exec_mode: "fork",
|
|
5810
5809
|
autorestart: true,
|
|
@@ -5843,17 +5842,17 @@ async function initServiceStructure(service, options = {}) {
|
|
|
5843
5842
|
if (!dryRun) await mkdir6(dir, { recursive: true });
|
|
5844
5843
|
created.push(dir);
|
|
5845
5844
|
}
|
|
5846
|
-
|
|
5847
|
-
if (
|
|
5848
|
-
|
|
5845
|
+
const ecosystemExisted = await pathExists4(paths.ecosystem);
|
|
5846
|
+
if (!dryRun) {
|
|
5847
|
+
await writeFile5(paths.ecosystem, buildEcosystemConfig(service, paths), { mode: 420 });
|
|
5848
|
+
}
|
|
5849
|
+
if (ecosystemExisted) {
|
|
5850
|
+
logger.info(`synced ${paths.ecosystem} from manifest`);
|
|
5849
5851
|
} else {
|
|
5850
|
-
if (!dryRun) {
|
|
5851
|
-
await writeFile5(paths.ecosystem, buildEcosystemConfig(service, paths), { mode: 420 });
|
|
5852
|
-
}
|
|
5853
|
-
ecosystemCreated = true;
|
|
5854
5852
|
created.push(paths.ecosystem);
|
|
5853
|
+
logger.info(`seeded ${paths.ecosystem}`);
|
|
5855
5854
|
}
|
|
5856
|
-
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] init-structure service=${service.name} dryRun=${dryRun} created=${created.length} skipped=${skipped.length}
|
|
5855
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] init-structure service=${service.name} dryRun=${dryRun} created=${created.length} skipped=${skipped.length} ecosystem=synced
|
|
5857
5856
|
`;
|
|
5858
5857
|
if (!dryRun) {
|
|
5859
5858
|
await mkdir6(paths.logs, { recursive: true });
|
|
@@ -5862,8 +5861,7 @@ async function initServiceStructure(service, options = {}) {
|
|
|
5862
5861
|
logger.info(`service=${service.name} appsRoot=${paths.root}`);
|
|
5863
5862
|
logger.info(`created: ${created.length ? created.join(", ") : "(none)"}`);
|
|
5864
5863
|
logger.info(`already present: ${skipped.length ? skipped.join(", ") : "(none)"}`);
|
|
5865
|
-
|
|
5866
|
-
return { paths, created, skipped, ecosystemCreated };
|
|
5864
|
+
return { paths, created, skipped, ecosystemCreated: !ecosystemExisted, ecosystemSynced: true };
|
|
5867
5865
|
}
|
|
5868
5866
|
|
|
5869
5867
|
// src/deploy/bootstrap-host.js
|
|
@@ -5960,11 +5958,55 @@ async function installLogrotate(service, options = {}) {
|
|
|
5960
5958
|
await runShell(`sudo cp '${tmp}' '${conf}'`, { logger });
|
|
5961
5959
|
logger.info(`logrotate config written: ${conf}`);
|
|
5962
5960
|
}
|
|
5961
|
+
var OPERATOR_SHELL_BEGIN = "# >>> mlsfarm-operator >>>";
|
|
5962
|
+
var OPERATOR_SHELL_END = "# <<< mlsfarm-operator <<<";
|
|
5963
|
+
async function installOperatorShell(service, options = {}) {
|
|
5964
|
+
const { user = "ubuntu", dryRun = false, logger = console } = options;
|
|
5965
|
+
const appsRoot = service.appsRoot;
|
|
5966
|
+
if (!appsRoot) {
|
|
5967
|
+
logger.warn("installOperatorShell: service.appsRoot missing \u2014 skipped");
|
|
5968
|
+
return;
|
|
5969
|
+
}
|
|
5970
|
+
const home = user === "ubuntu" || user === process.env.USER ? join10(homedir(), ".bashrc") : `/home/${user}/.bashrc`;
|
|
5971
|
+
const currentDir = join10(appsRoot, "current");
|
|
5972
|
+
const block = [
|
|
5973
|
+
OPERATOR_SHELL_BEGIN,
|
|
5974
|
+
"# Managed by cli-toolkit deploy bootstrap \u2014 do not edit by hand.",
|
|
5975
|
+
"export ENV=production",
|
|
5976
|
+
`if [ -d "${currentDir}" ]; then`,
|
|
5977
|
+
` cd "${currentDir}" || true`,
|
|
5978
|
+
"fi",
|
|
5979
|
+
OPERATOR_SHELL_END,
|
|
5980
|
+
""
|
|
5981
|
+
].join("\n");
|
|
5982
|
+
if (dryRun) {
|
|
5983
|
+
logger.info(`[dryRun] would update ${home} (ENV=production, cd ${currentDir})`);
|
|
5984
|
+
return;
|
|
5985
|
+
}
|
|
5986
|
+
let existing = "";
|
|
5987
|
+
if (await pathExists5(home)) {
|
|
5988
|
+
existing = await readFile4(home, "utf8");
|
|
5989
|
+
}
|
|
5990
|
+
const begin = existing.indexOf(OPERATOR_SHELL_BEGIN);
|
|
5991
|
+
const end = existing.indexOf(OPERATOR_SHELL_END);
|
|
5992
|
+
let next;
|
|
5993
|
+
if (begin !== -1 && end !== -1 && end > begin) {
|
|
5994
|
+
const afterEnd = end + OPERATOR_SHELL_END.length;
|
|
5995
|
+
const rest = existing.slice(afterEnd).replace(/^\n/, "");
|
|
5996
|
+
next = `${existing.slice(0, begin).replace(/\s*$/, "\n")}${block}${rest}`;
|
|
5997
|
+
} else {
|
|
5998
|
+
next = `${existing.replace(/\s*$/, "\n")}
|
|
5999
|
+
${block}`;
|
|
6000
|
+
}
|
|
6001
|
+
await writeFile6(home, next, { mode: 420 });
|
|
6002
|
+
logger.info(`operator shell: ${home} \u2192 ENV=production, cd ${currentDir}`);
|
|
6003
|
+
}
|
|
5963
6004
|
async function bootstrapHost(service, options = {}) {
|
|
5964
6005
|
const { deployKey = service.deployKey, user = "ubuntu", dryRun = false, logger = console } = options;
|
|
5965
6006
|
await ensurePm2Startup({ user, dryRun, logger });
|
|
5966
6007
|
if (deployKey) await installDeployKey(deployKey, { dryRun, logger });
|
|
5967
6008
|
await installLogrotate(service, { dryRun, logger });
|
|
6009
|
+
await installOperatorShell(service, { user, dryRun, logger });
|
|
5968
6010
|
logger.info("bootstrap-host complete");
|
|
5969
6011
|
}
|
|
5970
6012
|
|
|
@@ -7754,6 +7796,273 @@ var TaskGetLogs = class extends AbstractTask {
|
|
|
7754
7796
|
}
|
|
7755
7797
|
};
|
|
7756
7798
|
|
|
7799
|
+
// src/tasks/runtimeParams.js
|
|
7800
|
+
var LOOP_RUNTIME_KEYS = ["maxParallel", "pollMs", "claimJitterMs", "scanLimit"];
|
|
7801
|
+
var LOGGER_RUNTIME_KEYS = [
|
|
7802
|
+
"levels",
|
|
7803
|
+
"silent",
|
|
7804
|
+
"showLevel",
|
|
7805
|
+
"timestamp",
|
|
7806
|
+
"mode",
|
|
7807
|
+
"route",
|
|
7808
|
+
"prefix",
|
|
7809
|
+
"progressWithTimes",
|
|
7810
|
+
"progressThrottleMs"
|
|
7811
|
+
];
|
|
7812
|
+
var CONTROL_LANE_TASK_NAMES = ["stopRunner", "stop", "setRuntimeParam", "setRunnerParam"];
|
|
7813
|
+
function controlLaneTaskNames() {
|
|
7814
|
+
return [...CONTROL_LANE_TASK_NAMES];
|
|
7815
|
+
}
|
|
7816
|
+
function asPositiveInt(value, key, { min = 1 } = {}) {
|
|
7817
|
+
const n = Number(value);
|
|
7818
|
+
if (!Number.isFinite(n) || n < min) {
|
|
7819
|
+
throw new ParamError(
|
|
7820
|
+
`setRuntimeParam: ${key} must be a number >= ${min} (got ${JSON.stringify(value)})`
|
|
7821
|
+
);
|
|
7822
|
+
}
|
|
7823
|
+
return Math.floor(n);
|
|
7824
|
+
}
|
|
7825
|
+
function coerceRuntimeValue(key, value) {
|
|
7826
|
+
switch (key) {
|
|
7827
|
+
case "maxParallel":
|
|
7828
|
+
return asPositiveInt(value, key, { min: 1 });
|
|
7829
|
+
case "pollMs":
|
|
7830
|
+
return asPositiveInt(value, key, { min: 50 });
|
|
7831
|
+
case "claimJitterMs":
|
|
7832
|
+
return asPositiveInt(value, key, { min: 0 });
|
|
7833
|
+
case "scanLimit":
|
|
7834
|
+
return asPositiveInt(value, key, { min: 1 });
|
|
7835
|
+
case "silent":
|
|
7836
|
+
case "showLevel":
|
|
7837
|
+
case "timestamp":
|
|
7838
|
+
case "progressWithTimes":
|
|
7839
|
+
if (typeof value === "boolean") return value;
|
|
7840
|
+
if (value === "true" || value === "1") return true;
|
|
7841
|
+
if (value === "false" || value === "0") return false;
|
|
7842
|
+
throw new ParamError(
|
|
7843
|
+
`setRuntimeParam: ${key} must be boolean (got ${JSON.stringify(value)})`
|
|
7844
|
+
);
|
|
7845
|
+
case "progressThrottleMs":
|
|
7846
|
+
return asPositiveInt(value, key, { min: 0 });
|
|
7847
|
+
case "levels":
|
|
7848
|
+
case "mode":
|
|
7849
|
+
case "route":
|
|
7850
|
+
case "prefix":
|
|
7851
|
+
return value;
|
|
7852
|
+
default:
|
|
7853
|
+
return value;
|
|
7854
|
+
}
|
|
7855
|
+
}
|
|
7856
|
+
function ensureTasksRuntime(context, seed = {}) {
|
|
7857
|
+
if (!context.tasksRuntime || typeof context.tasksRuntime !== "object") {
|
|
7858
|
+
context.tasksRuntime = {};
|
|
7859
|
+
}
|
|
7860
|
+
const rt = context.tasksRuntime;
|
|
7861
|
+
if (rt.maxParallel === void 0) rt.maxParallel = seed.maxParallel ?? 32;
|
|
7862
|
+
if (rt.pollMs === void 0) rt.pollMs = seed.pollMs ?? 1e3;
|
|
7863
|
+
if (rt.claimJitterMs === void 0) rt.claimJitterMs = seed.claimJitterMs ?? 0;
|
|
7864
|
+
if (rt.scanLimit === void 0) rt.scanLimit = seed.scanLimit ?? 100;
|
|
7865
|
+
return rt;
|
|
7866
|
+
}
|
|
7867
|
+
async function applyRuntimeParam(context, key, value) {
|
|
7868
|
+
const k = String(key ?? "").trim();
|
|
7869
|
+
if (!k) throw new ParamError("setRuntimeParam: key is required");
|
|
7870
|
+
const runtime = ensureTasksRuntime(context);
|
|
7871
|
+
const next = coerceRuntimeValue(k, value);
|
|
7872
|
+
const previous = runtime[k];
|
|
7873
|
+
const applied = [];
|
|
7874
|
+
runtime[k] = next;
|
|
7875
|
+
applied.push("tasksRuntime");
|
|
7876
|
+
if (LOGGER_RUNTIME_KEYS.includes(k) && context.logger?.configure) {
|
|
7877
|
+
context.logger.configure({ [k]: next });
|
|
7878
|
+
applied.push("logger");
|
|
7879
|
+
}
|
|
7880
|
+
const hook = context.tasksRuntimeOnParam;
|
|
7881
|
+
if (typeof hook === "function") {
|
|
7882
|
+
await hook(k, next, runtime, context);
|
|
7883
|
+
applied.push("onRuntimeParam");
|
|
7884
|
+
}
|
|
7885
|
+
const reg = context.servicesRegistry;
|
|
7886
|
+
if (reg?.rowId && reg?.registryTable) {
|
|
7887
|
+
try {
|
|
7888
|
+
const loopSnapshot = {};
|
|
7889
|
+
for (const lk of LOOP_RUNTIME_KEYS) {
|
|
7890
|
+
if (runtime[lk] !== void 0) loopSnapshot[lk] = runtime[lk];
|
|
7891
|
+
}
|
|
7892
|
+
await updateServicesRegistryMetadata(context, reg, {
|
|
7893
|
+
runtime: loopSnapshot,
|
|
7894
|
+
runtimeUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7895
|
+
});
|
|
7896
|
+
applied.push("servicesRegistry");
|
|
7897
|
+
} catch (err) {
|
|
7898
|
+
context.logger?.warn?.(
|
|
7899
|
+
`[setRuntimeParam] registry metadata update failed: ${err?.message ?? String(err)}`
|
|
7900
|
+
);
|
|
7901
|
+
}
|
|
7902
|
+
}
|
|
7903
|
+
return { key: k, previous, next, applied };
|
|
7904
|
+
}
|
|
7905
|
+
async function applyRuntimePatch(context, patch) {
|
|
7906
|
+
if (!patch || typeof patch !== "object" || Array.isArray(patch)) {
|
|
7907
|
+
throw new ParamError("setRuntimeParam: patch must be a plain object");
|
|
7908
|
+
}
|
|
7909
|
+
const entries = Object.entries(patch);
|
|
7910
|
+
if (entries.length === 0) {
|
|
7911
|
+
throw new ParamError("setRuntimeParam: patch is empty");
|
|
7912
|
+
}
|
|
7913
|
+
const out = [];
|
|
7914
|
+
for (const [key, value] of entries) {
|
|
7915
|
+
out.push(await applyRuntimeParam(context, key, value));
|
|
7916
|
+
}
|
|
7917
|
+
return out;
|
|
7918
|
+
}
|
|
7919
|
+
function readLoopRuntime(context) {
|
|
7920
|
+
const rt = ensureTasksRuntime(context);
|
|
7921
|
+
return {
|
|
7922
|
+
maxParallel: Math.max(1, Number(rt.maxParallel) || 1),
|
|
7923
|
+
pollMs: Math.max(50, Number(rt.pollMs) || 1e3),
|
|
7924
|
+
claimJitterMs: Math.max(0, Number(rt.claimJitterMs) || 0),
|
|
7925
|
+
scanLimit: Math.max(1, Number(rt.scanLimit) || 100)
|
|
7926
|
+
};
|
|
7927
|
+
}
|
|
7928
|
+
|
|
7929
|
+
// src/tasks/coreTasks/TaskSetRuntimeParam.js
|
|
7930
|
+
var TaskSetRuntimeParam = class extends AbstractTask {
|
|
7931
|
+
static defaultWaitForResult = true;
|
|
7932
|
+
/**
|
|
7933
|
+
* @param {object} context
|
|
7934
|
+
* @param {Record<string, unknown>} [overrides]
|
|
7935
|
+
* @returns {Promise<object>}
|
|
7936
|
+
*/
|
|
7937
|
+
static async resolveParams(context, overrides = {}) {
|
|
7938
|
+
const main = await super.resolveParams(context, overrides);
|
|
7939
|
+
if (!main.serviceName && !main.serviceGroup) {
|
|
7940
|
+
throw new ParamError(
|
|
7941
|
+
"setRuntimeParam requires --serviceName (one instance) or --serviceGroup (broadcast to alive instances)"
|
|
7942
|
+
);
|
|
7943
|
+
}
|
|
7944
|
+
return main;
|
|
7945
|
+
}
|
|
7946
|
+
/**
|
|
7947
|
+
* @param {object} context
|
|
7948
|
+
* @param {Record<string, unknown>} [overrides]
|
|
7949
|
+
* @returns {Promise<{ key?: string, value?: unknown, patch?: Record<string, unknown> }>}
|
|
7950
|
+
*/
|
|
7951
|
+
static async resolveCustomParams(context, overrides = {}) {
|
|
7952
|
+
const merged = AbstractTask._mergeTypedParams(
|
|
7953
|
+
context,
|
|
7954
|
+
"task-set-runtime-param",
|
|
7955
|
+
{
|
|
7956
|
+
paramKey: "string",
|
|
7957
|
+
paramValue: "string",
|
|
7958
|
+
key: "string",
|
|
7959
|
+
value: "string"
|
|
7960
|
+
},
|
|
7961
|
+
overrides
|
|
7962
|
+
);
|
|
7963
|
+
if (merged.patch && typeof merged.patch === "object" && !Array.isArray(merged.patch)) {
|
|
7964
|
+
if (Object.keys(merged.patch).length === 0) {
|
|
7965
|
+
throw new ParamError("setRuntimeParam: patch is empty");
|
|
7966
|
+
}
|
|
7967
|
+
return { patch: { ...merged.patch } };
|
|
7968
|
+
}
|
|
7969
|
+
const key = merged.paramKey || merged.key;
|
|
7970
|
+
const value = merged.paramValue !== void 0 ? merged.paramValue : merged.value;
|
|
7971
|
+
if (!key) {
|
|
7972
|
+
throw new ParamError(
|
|
7973
|
+
`setRuntimeParam requires --paramKey/--paramValue, or --paramsJson '{"key":"maxParallel","value":16}' / '{"patch":{...}}'`
|
|
7974
|
+
);
|
|
7975
|
+
}
|
|
7976
|
+
let parsed = value;
|
|
7977
|
+
if (typeof value === "string") {
|
|
7978
|
+
const t = value.trim();
|
|
7979
|
+
if (t === "true") parsed = true;
|
|
7980
|
+
else if (t === "false") parsed = false;
|
|
7981
|
+
else if (t !== "" && !Number.isNaN(Number(t)) && /^-?\d+(\.\d+)?$/.test(t)) {
|
|
7982
|
+
parsed = Number(t);
|
|
7983
|
+
} else if (t.startsWith("{") && t.endsWith("}") || t.startsWith("[") && t.endsWith("]") || t.startsWith('"') && t.endsWith('"')) {
|
|
7984
|
+
try {
|
|
7985
|
+
parsed = JSON.parse(t);
|
|
7986
|
+
} catch {
|
|
7987
|
+
parsed = value;
|
|
7988
|
+
}
|
|
7989
|
+
}
|
|
7990
|
+
}
|
|
7991
|
+
return { key: String(key), value: parsed };
|
|
7992
|
+
}
|
|
7993
|
+
/**
|
|
7994
|
+
* Enqueue one or many setRuntimeParam tasks. Prefer this over a bare
|
|
7995
|
+
* `enqueueTask` when broadcasting to a service group.
|
|
7996
|
+
*
|
|
7997
|
+
* @param {object} context
|
|
7998
|
+
* @param {Record<string, unknown>} [overrides]
|
|
7999
|
+
* @returns {Promise<{ ids: string[], targets: string[] }>}
|
|
8000
|
+
*/
|
|
8001
|
+
static async enqueue(context, overrides = {}) {
|
|
8002
|
+
const payload = await this.resolveParams(context, { ...overrides, name: "setRuntimeParam" });
|
|
8003
|
+
const queueName = payload.queueName ?? "tasks";
|
|
8004
|
+
if (payload.serviceName) {
|
|
8005
|
+
const id = await enqueueTask(context, payload);
|
|
8006
|
+
return { ids: [id], targets: [payload.serviceName] };
|
|
8007
|
+
}
|
|
8008
|
+
const group = String(payload.serviceGroup || "").trim();
|
|
8009
|
+
if (!group) {
|
|
8010
|
+
throw new ParamError("setRuntimeParam.enqueue: serviceGroup required for broadcast");
|
|
8011
|
+
}
|
|
8012
|
+
const alive = await listServicesRegistry(context, {
|
|
8013
|
+
queueName,
|
|
8014
|
+
serviceGroup: group,
|
|
8015
|
+
staleMs: overrides.staleMs ?? 45e3
|
|
8016
|
+
});
|
|
8017
|
+
if (!alive.length) {
|
|
8018
|
+
throw new ParamError(
|
|
8019
|
+
`setRuntimeParam: no alive services in group="${group}" queue="${queueName}"`
|
|
8020
|
+
);
|
|
8021
|
+
}
|
|
8022
|
+
const ids = [];
|
|
8023
|
+
const targets = [];
|
|
8024
|
+
for (const reg of alive) {
|
|
8025
|
+
const id = await enqueueTask(context, {
|
|
8026
|
+
...payload,
|
|
8027
|
+
serviceGroup: group,
|
|
8028
|
+
serviceName: reg.service_name,
|
|
8029
|
+
serverName: reg.server_name ?? null,
|
|
8030
|
+
instanceNumber: reg.instance_number ?? null
|
|
8031
|
+
});
|
|
8032
|
+
ids.push(id);
|
|
8033
|
+
targets.push(reg.service_name);
|
|
8034
|
+
}
|
|
8035
|
+
context.logger?.info?.(
|
|
8036
|
+
`[setRuntimeParam] broadcast to ${targets.length} instance(s) in group=${group}: ${targets.join(", ")}`
|
|
8037
|
+
);
|
|
8038
|
+
return { ids, targets };
|
|
8039
|
+
}
|
|
8040
|
+
/**
|
|
8041
|
+
* @returns {Promise<{ success: true, results: object }>}
|
|
8042
|
+
*/
|
|
8043
|
+
async run() {
|
|
8044
|
+
const params = this.task?.params ?? {};
|
|
8045
|
+
let changes;
|
|
8046
|
+
if (params.patch && typeof params.patch === "object") {
|
|
8047
|
+
changes = await applyRuntimePatch(this.context, params.patch);
|
|
8048
|
+
} else {
|
|
8049
|
+
changes = [await applyRuntimeParam(this.context, params.key, params.value)];
|
|
8050
|
+
}
|
|
8051
|
+
const summary = changes.map((c) => `${c.key}: ${JSON.stringify(c.previous)} \u2192 ${JSON.stringify(c.next)}`);
|
|
8052
|
+
this.context.logger.warn?.(
|
|
8053
|
+
`[TaskSetRuntimeParam] applied on ${this.context.servicesRegistry?.serviceName ?? "runner"}: ${summary.join("; ")}`
|
|
8054
|
+
);
|
|
8055
|
+
return {
|
|
8056
|
+
success: true,
|
|
8057
|
+
results: {
|
|
8058
|
+
runtimeParamApplied: true,
|
|
8059
|
+
changes,
|
|
8060
|
+
runtime: { ...this.context.tasksRuntime ?? {} }
|
|
8061
|
+
}
|
|
8062
|
+
};
|
|
8063
|
+
}
|
|
8064
|
+
};
|
|
8065
|
+
|
|
7757
8066
|
// src/tasks/TasksRegistry.js
|
|
7758
8067
|
var TasksRegistry = class _TasksRegistry {
|
|
7759
8068
|
/**
|
|
@@ -7772,7 +8081,7 @@ var TasksRegistry = class _TasksRegistry {
|
|
|
7772
8081
|
* @returns {TasksRegistry}
|
|
7773
8082
|
*/
|
|
7774
8083
|
static withCoreTasks() {
|
|
7775
|
-
return new _TasksRegistry().add("ping", TaskPing).add("sampleProcess", TaskSampleProcess).add("shellCommand", TaskShellCommand).add("systemInfo", TaskSystemInfo).add("info", TaskSystemInfo).add("taskSumAB", TaskSumAB).add("stopRunner", TaskStopRunner).add("stop", TaskStopRunner).add("getLogs", TaskGetLogs);
|
|
8084
|
+
return new _TasksRegistry().add("ping", TaskPing).add("sampleProcess", TaskSampleProcess).add("shellCommand", TaskShellCommand).add("systemInfo", TaskSystemInfo).add("info", TaskSystemInfo).add("taskSumAB", TaskSumAB).add("stopRunner", TaskStopRunner).add("stop", TaskStopRunner).add("getLogs", TaskGetLogs).add("setRuntimeParam", TaskSetRuntimeParam).add("setRunnerParam", TaskSetRuntimeParam);
|
|
7776
8085
|
}
|
|
7777
8086
|
/**
|
|
7778
8087
|
* Register a single task class under a name. Overwrites any previous entry.
|
|
@@ -7878,7 +8187,9 @@ var SERVICE_TASK_NAMES = [
|
|
|
7878
8187
|
"shellCommand",
|
|
7879
8188
|
"systemInfo",
|
|
7880
8189
|
"info",
|
|
7881
|
-
"getLogs"
|
|
8190
|
+
"getLogs",
|
|
8191
|
+
"setRuntimeParam",
|
|
8192
|
+
"setRunnerParam"
|
|
7882
8193
|
];
|
|
7883
8194
|
function normalizeAllowedTasks(value) {
|
|
7884
8195
|
if (!value) return void 0;
|
|
@@ -8305,18 +8616,23 @@ async function claimNextRunnableTask(context, tasksTable, serviceGroup, registry
|
|
|
8305
8616
|
async function runTasksLoop(context, options) {
|
|
8306
8617
|
const queueName = options.queueName ?? "tasks";
|
|
8307
8618
|
const target = options.target;
|
|
8308
|
-
const pollMs = options.pollMs ?? 1e3;
|
|
8309
|
-
const claimJitterMs = options.claimJitterMs ?? 0;
|
|
8310
|
-
const maxParallel = options.maxParallel ?? 32;
|
|
8311
|
-
const scanLimit = options.scanLimit ?? 100;
|
|
8312
8619
|
const allowedTasks = normalizeAllowedTasks(options.allowedTasks);
|
|
8313
8620
|
const registry = normalizeRegistry(options.registry);
|
|
8314
8621
|
const { tasksTable, historyTable } = queueToTableNames(queueName);
|
|
8315
8622
|
if (!target) throw new Error("runTasksLoop: target is required");
|
|
8316
8623
|
context.tasksQueueName = queueName;
|
|
8624
|
+
ensureTasksRuntime(context, {
|
|
8625
|
+
maxParallel: options.maxParallel ?? 32,
|
|
8626
|
+
pollMs: options.pollMs ?? 1e3,
|
|
8627
|
+
claimJitterMs: options.claimJitterMs ?? 0,
|
|
8628
|
+
scanLimit: options.scanLimit ?? 100
|
|
8629
|
+
});
|
|
8630
|
+
if (typeof options.onRuntimeParam === "function") {
|
|
8631
|
+
context.tasksRuntimeOnParam = options.onRuntimeParam;
|
|
8632
|
+
}
|
|
8317
8633
|
const runningPromises = /* @__PURE__ */ new Set();
|
|
8318
8634
|
const runningTaskInstances = /* @__PURE__ */ new Map();
|
|
8319
|
-
let
|
|
8635
|
+
let runningControlPromise = null;
|
|
8320
8636
|
let stopRequested = false;
|
|
8321
8637
|
let stopAllowanceMs = 5e3;
|
|
8322
8638
|
context.tasksRunnerStop = false;
|
|
@@ -8327,9 +8643,16 @@ async function runTasksLoop(context, options) {
|
|
|
8327
8643
|
if (hbGroup) {
|
|
8328
8644
|
const hbIntervalMs = options.runnerHeartbeatIntervalMs ?? 1e4;
|
|
8329
8645
|
const staleMs = options.runnerHeartbeatStaleMs ?? 45e3;
|
|
8646
|
+
const loop0 = readLoopRuntime(context);
|
|
8330
8647
|
const defaultMeta = {
|
|
8331
8648
|
component: "tasks-runner",
|
|
8332
|
-
allowedTasks: allowedTasks?.length ? allowedTasks.join(",") : "all"
|
|
8649
|
+
allowedTasks: allowedTasks?.length ? allowedTasks.join(",") : "all",
|
|
8650
|
+
runtime: {
|
|
8651
|
+
maxParallel: loop0.maxParallel,
|
|
8652
|
+
pollMs: loop0.pollMs,
|
|
8653
|
+
claimJitterMs: loop0.claimJitterMs,
|
|
8654
|
+
scanLimit: loop0.scanLimit
|
|
8655
|
+
}
|
|
8333
8656
|
};
|
|
8334
8657
|
registryReg = await registerInServicesRegistry(context, {
|
|
8335
8658
|
queueName,
|
|
@@ -8342,6 +8665,7 @@ async function runTasksLoop(context, options) {
|
|
|
8342
8665
|
enforceMaxInstances: options.runnerEnforceMaxInstances ?? true,
|
|
8343
8666
|
metadata: options.runnerMetadata ?? defaultMeta
|
|
8344
8667
|
});
|
|
8668
|
+
context.servicesRegistry = registryReg;
|
|
8345
8669
|
runnerIdentity = {
|
|
8346
8670
|
service_name: registryReg.serviceName,
|
|
8347
8671
|
server_name: os3.hostname(),
|
|
@@ -8355,22 +8679,23 @@ async function runTasksLoop(context, options) {
|
|
|
8355
8679
|
}
|
|
8356
8680
|
try {
|
|
8357
8681
|
while (!context.isStop() && !stopRequested && context.tasksRunnerStop !== true) {
|
|
8358
|
-
|
|
8359
|
-
|
|
8682
|
+
const { maxParallel, pollMs, claimJitterMs, scanLimit } = readLoopRuntime(context);
|
|
8683
|
+
if (!runningControlPromise) {
|
|
8684
|
+
const claimedControlTask = await claimNextRunnableTask(
|
|
8360
8685
|
context,
|
|
8361
8686
|
tasksTable,
|
|
8362
8687
|
target,
|
|
8363
8688
|
registry,
|
|
8364
8689
|
10,
|
|
8365
|
-
|
|
8690
|
+
controlLaneTaskNames(),
|
|
8366
8691
|
runnerIdentity
|
|
8367
8692
|
);
|
|
8368
|
-
if (
|
|
8369
|
-
|
|
8693
|
+
if (claimedControlTask) {
|
|
8694
|
+
runningControlPromise = executeClaimedTask(
|
|
8370
8695
|
context,
|
|
8371
8696
|
tasksTable,
|
|
8372
8697
|
historyTable,
|
|
8373
|
-
|
|
8698
|
+
claimedControlTask,
|
|
8374
8699
|
registry,
|
|
8375
8700
|
runningTaskInstances
|
|
8376
8701
|
).then(async (outcome) => {
|
|
@@ -8381,7 +8706,7 @@ async function runTasksLoop(context, options) {
|
|
|
8381
8706
|
await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
|
|
8382
8707
|
}
|
|
8383
8708
|
}).finally(() => {
|
|
8384
|
-
|
|
8709
|
+
runningControlPromise = null;
|
|
8385
8710
|
});
|
|
8386
8711
|
}
|
|
8387
8712
|
}
|
|
@@ -8412,8 +8737,8 @@ async function runTasksLoop(context, options) {
|
|
|
8412
8737
|
runningPromises.add(p);
|
|
8413
8738
|
}
|
|
8414
8739
|
const wakePromises = [...runningPromises];
|
|
8415
|
-
if (
|
|
8416
|
-
wakePromises.push(
|
|
8740
|
+
if (runningControlPromise) {
|
|
8741
|
+
wakePromises.push(runningControlPromise);
|
|
8417
8742
|
}
|
|
8418
8743
|
if (wakePromises.length === 0) {
|
|
8419
8744
|
await sleepMs(pollMs);
|
|
@@ -8641,6 +8966,8 @@ export {
|
|
|
8641
8966
|
FooterPresets,
|
|
8642
8967
|
GridCell,
|
|
8643
8968
|
InputField,
|
|
8969
|
+
LOGGER_RUNTIME_KEYS,
|
|
8970
|
+
LOOP_RUNTIME_KEYS,
|
|
8644
8971
|
ListComponent,
|
|
8645
8972
|
ListItem,
|
|
8646
8973
|
MultiColumnListComponent,
|
|
@@ -8659,6 +8986,7 @@ export {
|
|
|
8659
8986
|
TaskGetLogs,
|
|
8660
8987
|
TaskPing,
|
|
8661
8988
|
TaskSampleProcess,
|
|
8989
|
+
TaskSetRuntimeParam,
|
|
8662
8990
|
TaskShellCommand,
|
|
8663
8991
|
TaskStopRunner,
|
|
8664
8992
|
TaskSumAB,
|
|
@@ -8670,12 +8998,16 @@ export {
|
|
|
8670
8998
|
activateRelease,
|
|
8671
8999
|
appendDeployLog,
|
|
8672
9000
|
appendTaskIpcLog,
|
|
9001
|
+
applyRuntimeParam,
|
|
9002
|
+
applyRuntimePatch,
|
|
8673
9003
|
bootstrapHost,
|
|
8674
9004
|
buildBreadcrumb,
|
|
8675
9005
|
buildDetailBreadcrumb,
|
|
8676
9006
|
buildFooter,
|
|
8677
9007
|
bumpPatchVersion,
|
|
8678
9008
|
cloneRepo,
|
|
9009
|
+
coerceRuntimeValue,
|
|
9010
|
+
controlLaneTaskNames,
|
|
8679
9011
|
convertPattern,
|
|
8680
9012
|
createRelease,
|
|
8681
9013
|
defaultFileSynopsisFunction,
|
|
@@ -8697,11 +9029,13 @@ export {
|
|
|
8697
9029
|
ensureSchemaEverywhere,
|
|
8698
9030
|
ensureTable,
|
|
8699
9031
|
ensureTaskTables,
|
|
9032
|
+
ensureTasksRuntime,
|
|
8700
9033
|
flushTaskIpcLogs,
|
|
8701
9034
|
getArgsInstance,
|
|
8702
9035
|
createElement2 as h,
|
|
8703
9036
|
initServiceStructure,
|
|
8704
9037
|
installDeps,
|
|
9038
|
+
installOperatorShell,
|
|
8705
9039
|
ipcFileLogsTableNameForSourceResource,
|
|
8706
9040
|
joiEdateType,
|
|
8707
9041
|
joiStringArrayType,
|
|
@@ -8727,6 +9061,7 @@ export {
|
|
|
8727
9061
|
pullRepo,
|
|
8728
9062
|
queueToTableNames,
|
|
8729
9063
|
readCurrentRelease,
|
|
9064
|
+
readLoopRuntime,
|
|
8730
9065
|
readReleaseBuildInfo,
|
|
8731
9066
|
readTaskIpcLogsSnapshot,
|
|
8732
9067
|
registerInServicesRegistry,
|