@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/cli-runner.js
CHANGED
|
@@ -2687,6 +2687,9 @@ async function init(flow2, opts = {}) {
|
|
|
2687
2687
|
if (context) {
|
|
2688
2688
|
await runRegisteredCleanups(context);
|
|
2689
2689
|
}
|
|
2690
|
+
if (process.exitCode && process.exitCode !== 0) {
|
|
2691
|
+
process.exit(process.exitCode);
|
|
2692
|
+
}
|
|
2690
2693
|
}
|
|
2691
2694
|
}
|
|
2692
2695
|
|
|
@@ -3966,6 +3969,51 @@ async function dropLegacyTaskNameColumn(db, tableNames, { dryRun, log, label })
|
|
|
3966
3969
|
}
|
|
3967
3970
|
return actions;
|
|
3968
3971
|
}
|
|
3972
|
+
async function enqueueTask(context, options) {
|
|
3973
|
+
const db = getDb(context);
|
|
3974
|
+
const queueName = options.queueName ?? "tasks";
|
|
3975
|
+
const { tasksTable } = queueToTableNames(queueName);
|
|
3976
|
+
const id = randomUUID();
|
|
3977
|
+
const name = options.name ?? options.task;
|
|
3978
|
+
if (!name) {
|
|
3979
|
+
throw new Error("enqueueTask: name (or task) is required");
|
|
3980
|
+
}
|
|
3981
|
+
const schedule = options.schedule?.trim() ? options.schedule : null;
|
|
3982
|
+
let nextRunAt = null;
|
|
3983
|
+
if (options.nextRunAt !== void 0) {
|
|
3984
|
+
nextRunAt = options.nextRunAt == null ? null : new Date(options.nextRunAt);
|
|
3985
|
+
} else if (schedule) {
|
|
3986
|
+
nextRunAt = nextTimeMatch(schedule, /* @__PURE__ */ new Date());
|
|
3987
|
+
}
|
|
3988
|
+
const row = {
|
|
3989
|
+
id,
|
|
3990
|
+
name,
|
|
3991
|
+
params: toJsonColumn(options.params ?? null),
|
|
3992
|
+
opid: options.opid ?? null,
|
|
3993
|
+
priority: options.priority ?? 50,
|
|
3994
|
+
schedule,
|
|
3995
|
+
next_run_at: nextRunAt,
|
|
3996
|
+
service_group: options.serviceGroup ?? null,
|
|
3997
|
+
instance_number: options.instanceNumber ?? null,
|
|
3998
|
+
service_name: options.serviceName ?? null,
|
|
3999
|
+
server_name: options.serverName ?? null,
|
|
4000
|
+
status: "idle",
|
|
4001
|
+
status_changed_at: db.fn.now()
|
|
4002
|
+
};
|
|
4003
|
+
if (await tableHasLegacyTaskColumn(db, tasksTable)) {
|
|
4004
|
+
row.task = name;
|
|
4005
|
+
}
|
|
4006
|
+
await db(tasksTable).insert(row);
|
|
4007
|
+
return id;
|
|
4008
|
+
}
|
|
4009
|
+
var legacyTaskColumnCache = /* @__PURE__ */ new Map();
|
|
4010
|
+
async function tableHasLegacyTaskColumn(db, tableName) {
|
|
4011
|
+
const key = `${db?.config?.name ?? "db"}:${tableName}`;
|
|
4012
|
+
if (!legacyTaskColumnCache.has(key)) {
|
|
4013
|
+
legacyTaskColumnCache.set(key, await db.schema.hasColumn(tableName, "task"));
|
|
4014
|
+
}
|
|
4015
|
+
return legacyTaskColumnCache.get(key);
|
|
4016
|
+
}
|
|
3969
4017
|
async function updateTaskProgress(context, tasksTable, taskId, progress) {
|
|
3970
4018
|
const db = getDb(context);
|
|
3971
4019
|
await db(tasksTable).where({ id: taskId }).update({
|
|
@@ -3981,6 +4029,19 @@ function getDb2(context) {
|
|
|
3981
4029
|
}
|
|
3982
4030
|
return db;
|
|
3983
4031
|
}
|
|
4032
|
+
function parseMetadataColumn(value) {
|
|
4033
|
+
if (!value) return {};
|
|
4034
|
+
if (typeof value === "object" && !Array.isArray(value)) return value;
|
|
4035
|
+
if (typeof value === "string") {
|
|
4036
|
+
try {
|
|
4037
|
+
const p = JSON.parse(value);
|
|
4038
|
+
return p && typeof p === "object" && !Array.isArray(value) ? p : {};
|
|
4039
|
+
} catch {
|
|
4040
|
+
return {};
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
4043
|
+
return {};
|
|
4044
|
+
}
|
|
3984
4045
|
var DEFAULT_GROUP_MAX_INSTANCES = {
|
|
3985
4046
|
intake: 1,
|
|
3986
4047
|
harvest: 1,
|
|
@@ -4179,11 +4240,33 @@ async function touchServicesRegistry(context, registration) {
|
|
|
4179
4240
|
pid
|
|
4180
4241
|
});
|
|
4181
4242
|
}
|
|
4243
|
+
async function updateServicesRegistryMetadata(context, registration, patch) {
|
|
4244
|
+
const db = getDb2(context);
|
|
4245
|
+
const row = await db(registration.registryTable).where({ id: registration.rowId }).first();
|
|
4246
|
+
const prev = parseMetadataColumn(row?.metadata);
|
|
4247
|
+
const merged = { ...prev, ...patch };
|
|
4248
|
+
await db(registration.registryTable).where({ id: registration.rowId }).update({
|
|
4249
|
+
metadata: toJsonColumn(merged),
|
|
4250
|
+
last_seen_at: db.fn.now()
|
|
4251
|
+
});
|
|
4252
|
+
context.logger.info?.(`[services-registry] metadata updated for ${registration.serviceName}`);
|
|
4253
|
+
}
|
|
4182
4254
|
async function unregisterServicesRegistry(context, registration) {
|
|
4183
4255
|
const db = getDb2(context);
|
|
4184
4256
|
await db(registration.registryTable).where({ id: registration.rowId }).delete();
|
|
4185
4257
|
context.logger.info?.(`[services-registry] unregistered name=${registration.serviceName} id=${registration.rowId}`);
|
|
4186
4258
|
}
|
|
4259
|
+
async function listServicesRegistry(context, options = { queueName: "tasks" }) {
|
|
4260
|
+
const db = getDb2(context);
|
|
4261
|
+
const staleMs = options.staleMs ?? 6e4;
|
|
4262
|
+
const cutoff = new Date(Date.now() - staleMs);
|
|
4263
|
+
const table = queueToTableNames(options.queueName).registryTable;
|
|
4264
|
+
let q = db(table).where("last_seen_at", ">", cutoff).orderBy([{ column: "service_group", order: "asc" }, { column: "service_name", order: "asc" }]);
|
|
4265
|
+
if (options.serviceGroup?.trim()) {
|
|
4266
|
+
q = q.where({ service_group: options.serviceGroup.trim() });
|
|
4267
|
+
}
|
|
4268
|
+
return await q;
|
|
4269
|
+
}
|
|
4187
4270
|
|
|
4188
4271
|
// src/tasks/taskLogs.js
|
|
4189
4272
|
import path4 from "path";
|
|
@@ -6142,6 +6225,273 @@ var TaskGetLogs = class extends AbstractTask {
|
|
|
6142
6225
|
}
|
|
6143
6226
|
};
|
|
6144
6227
|
|
|
6228
|
+
// src/tasks/runtimeParams.js
|
|
6229
|
+
var LOOP_RUNTIME_KEYS = ["maxParallel", "pollMs", "claimJitterMs", "scanLimit"];
|
|
6230
|
+
var LOGGER_RUNTIME_KEYS = [
|
|
6231
|
+
"levels",
|
|
6232
|
+
"silent",
|
|
6233
|
+
"showLevel",
|
|
6234
|
+
"timestamp",
|
|
6235
|
+
"mode",
|
|
6236
|
+
"route",
|
|
6237
|
+
"prefix",
|
|
6238
|
+
"progressWithTimes",
|
|
6239
|
+
"progressThrottleMs"
|
|
6240
|
+
];
|
|
6241
|
+
var CONTROL_LANE_TASK_NAMES = ["stopRunner", "stop", "setRuntimeParam", "setRunnerParam"];
|
|
6242
|
+
function controlLaneTaskNames() {
|
|
6243
|
+
return [...CONTROL_LANE_TASK_NAMES];
|
|
6244
|
+
}
|
|
6245
|
+
function asPositiveInt(value, key, { min = 1 } = {}) {
|
|
6246
|
+
const n = Number(value);
|
|
6247
|
+
if (!Number.isFinite(n) || n < min) {
|
|
6248
|
+
throw new ParamError(
|
|
6249
|
+
`setRuntimeParam: ${key} must be a number >= ${min} (got ${JSON.stringify(value)})`
|
|
6250
|
+
);
|
|
6251
|
+
}
|
|
6252
|
+
return Math.floor(n);
|
|
6253
|
+
}
|
|
6254
|
+
function coerceRuntimeValue(key, value) {
|
|
6255
|
+
switch (key) {
|
|
6256
|
+
case "maxParallel":
|
|
6257
|
+
return asPositiveInt(value, key, { min: 1 });
|
|
6258
|
+
case "pollMs":
|
|
6259
|
+
return asPositiveInt(value, key, { min: 50 });
|
|
6260
|
+
case "claimJitterMs":
|
|
6261
|
+
return asPositiveInt(value, key, { min: 0 });
|
|
6262
|
+
case "scanLimit":
|
|
6263
|
+
return asPositiveInt(value, key, { min: 1 });
|
|
6264
|
+
case "silent":
|
|
6265
|
+
case "showLevel":
|
|
6266
|
+
case "timestamp":
|
|
6267
|
+
case "progressWithTimes":
|
|
6268
|
+
if (typeof value === "boolean") return value;
|
|
6269
|
+
if (value === "true" || value === "1") return true;
|
|
6270
|
+
if (value === "false" || value === "0") return false;
|
|
6271
|
+
throw new ParamError(
|
|
6272
|
+
`setRuntimeParam: ${key} must be boolean (got ${JSON.stringify(value)})`
|
|
6273
|
+
);
|
|
6274
|
+
case "progressThrottleMs":
|
|
6275
|
+
return asPositiveInt(value, key, { min: 0 });
|
|
6276
|
+
case "levels":
|
|
6277
|
+
case "mode":
|
|
6278
|
+
case "route":
|
|
6279
|
+
case "prefix":
|
|
6280
|
+
return value;
|
|
6281
|
+
default:
|
|
6282
|
+
return value;
|
|
6283
|
+
}
|
|
6284
|
+
}
|
|
6285
|
+
function ensureTasksRuntime(context, seed = {}) {
|
|
6286
|
+
if (!context.tasksRuntime || typeof context.tasksRuntime !== "object") {
|
|
6287
|
+
context.tasksRuntime = {};
|
|
6288
|
+
}
|
|
6289
|
+
const rt = context.tasksRuntime;
|
|
6290
|
+
if (rt.maxParallel === void 0) rt.maxParallel = seed.maxParallel ?? 32;
|
|
6291
|
+
if (rt.pollMs === void 0) rt.pollMs = seed.pollMs ?? 1e3;
|
|
6292
|
+
if (rt.claimJitterMs === void 0) rt.claimJitterMs = seed.claimJitterMs ?? 0;
|
|
6293
|
+
if (rt.scanLimit === void 0) rt.scanLimit = seed.scanLimit ?? 100;
|
|
6294
|
+
return rt;
|
|
6295
|
+
}
|
|
6296
|
+
async function applyRuntimeParam(context, key, value) {
|
|
6297
|
+
const k = String(key ?? "").trim();
|
|
6298
|
+
if (!k) throw new ParamError("setRuntimeParam: key is required");
|
|
6299
|
+
const runtime = ensureTasksRuntime(context);
|
|
6300
|
+
const next = coerceRuntimeValue(k, value);
|
|
6301
|
+
const previous = runtime[k];
|
|
6302
|
+
const applied = [];
|
|
6303
|
+
runtime[k] = next;
|
|
6304
|
+
applied.push("tasksRuntime");
|
|
6305
|
+
if (LOGGER_RUNTIME_KEYS.includes(k) && context.logger?.configure) {
|
|
6306
|
+
context.logger.configure({ [k]: next });
|
|
6307
|
+
applied.push("logger");
|
|
6308
|
+
}
|
|
6309
|
+
const hook = context.tasksRuntimeOnParam;
|
|
6310
|
+
if (typeof hook === "function") {
|
|
6311
|
+
await hook(k, next, runtime, context);
|
|
6312
|
+
applied.push("onRuntimeParam");
|
|
6313
|
+
}
|
|
6314
|
+
const reg = context.servicesRegistry;
|
|
6315
|
+
if (reg?.rowId && reg?.registryTable) {
|
|
6316
|
+
try {
|
|
6317
|
+
const loopSnapshot = {};
|
|
6318
|
+
for (const lk of LOOP_RUNTIME_KEYS) {
|
|
6319
|
+
if (runtime[lk] !== void 0) loopSnapshot[lk] = runtime[lk];
|
|
6320
|
+
}
|
|
6321
|
+
await updateServicesRegistryMetadata(context, reg, {
|
|
6322
|
+
runtime: loopSnapshot,
|
|
6323
|
+
runtimeUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6324
|
+
});
|
|
6325
|
+
applied.push("servicesRegistry");
|
|
6326
|
+
} catch (err) {
|
|
6327
|
+
context.logger?.warn?.(
|
|
6328
|
+
`[setRuntimeParam] registry metadata update failed: ${err?.message ?? String(err)}`
|
|
6329
|
+
);
|
|
6330
|
+
}
|
|
6331
|
+
}
|
|
6332
|
+
return { key: k, previous, next, applied };
|
|
6333
|
+
}
|
|
6334
|
+
async function applyRuntimePatch(context, patch) {
|
|
6335
|
+
if (!patch || typeof patch !== "object" || Array.isArray(patch)) {
|
|
6336
|
+
throw new ParamError("setRuntimeParam: patch must be a plain object");
|
|
6337
|
+
}
|
|
6338
|
+
const entries = Object.entries(patch);
|
|
6339
|
+
if (entries.length === 0) {
|
|
6340
|
+
throw new ParamError("setRuntimeParam: patch is empty");
|
|
6341
|
+
}
|
|
6342
|
+
const out = [];
|
|
6343
|
+
for (const [key, value] of entries) {
|
|
6344
|
+
out.push(await applyRuntimeParam(context, key, value));
|
|
6345
|
+
}
|
|
6346
|
+
return out;
|
|
6347
|
+
}
|
|
6348
|
+
function readLoopRuntime(context) {
|
|
6349
|
+
const rt = ensureTasksRuntime(context);
|
|
6350
|
+
return {
|
|
6351
|
+
maxParallel: Math.max(1, Number(rt.maxParallel) || 1),
|
|
6352
|
+
pollMs: Math.max(50, Number(rt.pollMs) || 1e3),
|
|
6353
|
+
claimJitterMs: Math.max(0, Number(rt.claimJitterMs) || 0),
|
|
6354
|
+
scanLimit: Math.max(1, Number(rt.scanLimit) || 100)
|
|
6355
|
+
};
|
|
6356
|
+
}
|
|
6357
|
+
|
|
6358
|
+
// src/tasks/coreTasks/TaskSetRuntimeParam.js
|
|
6359
|
+
var TaskSetRuntimeParam = class extends AbstractTask {
|
|
6360
|
+
static defaultWaitForResult = true;
|
|
6361
|
+
/**
|
|
6362
|
+
* @param {object} context
|
|
6363
|
+
* @param {Record<string, unknown>} [overrides]
|
|
6364
|
+
* @returns {Promise<object>}
|
|
6365
|
+
*/
|
|
6366
|
+
static async resolveParams(context, overrides = {}) {
|
|
6367
|
+
const main = await super.resolveParams(context, overrides);
|
|
6368
|
+
if (!main.serviceName && !main.serviceGroup) {
|
|
6369
|
+
throw new ParamError(
|
|
6370
|
+
"setRuntimeParam requires --serviceName (one instance) or --serviceGroup (broadcast to alive instances)"
|
|
6371
|
+
);
|
|
6372
|
+
}
|
|
6373
|
+
return main;
|
|
6374
|
+
}
|
|
6375
|
+
/**
|
|
6376
|
+
* @param {object} context
|
|
6377
|
+
* @param {Record<string, unknown>} [overrides]
|
|
6378
|
+
* @returns {Promise<{ key?: string, value?: unknown, patch?: Record<string, unknown> }>}
|
|
6379
|
+
*/
|
|
6380
|
+
static async resolveCustomParams(context, overrides = {}) {
|
|
6381
|
+
const merged = AbstractTask._mergeTypedParams(
|
|
6382
|
+
context,
|
|
6383
|
+
"task-set-runtime-param",
|
|
6384
|
+
{
|
|
6385
|
+
paramKey: "string",
|
|
6386
|
+
paramValue: "string",
|
|
6387
|
+
key: "string",
|
|
6388
|
+
value: "string"
|
|
6389
|
+
},
|
|
6390
|
+
overrides
|
|
6391
|
+
);
|
|
6392
|
+
if (merged.patch && typeof merged.patch === "object" && !Array.isArray(merged.patch)) {
|
|
6393
|
+
if (Object.keys(merged.patch).length === 0) {
|
|
6394
|
+
throw new ParamError("setRuntimeParam: patch is empty");
|
|
6395
|
+
}
|
|
6396
|
+
return { patch: { ...merged.patch } };
|
|
6397
|
+
}
|
|
6398
|
+
const key = merged.paramKey || merged.key;
|
|
6399
|
+
const value = merged.paramValue !== void 0 ? merged.paramValue : merged.value;
|
|
6400
|
+
if (!key) {
|
|
6401
|
+
throw new ParamError(
|
|
6402
|
+
`setRuntimeParam requires --paramKey/--paramValue, or --paramsJson '{"key":"maxParallel","value":16}' / '{"patch":{...}}'`
|
|
6403
|
+
);
|
|
6404
|
+
}
|
|
6405
|
+
let parsed = value;
|
|
6406
|
+
if (typeof value === "string") {
|
|
6407
|
+
const t = value.trim();
|
|
6408
|
+
if (t === "true") parsed = true;
|
|
6409
|
+
else if (t === "false") parsed = false;
|
|
6410
|
+
else if (t !== "" && !Number.isNaN(Number(t)) && /^-?\d+(\.\d+)?$/.test(t)) {
|
|
6411
|
+
parsed = Number(t);
|
|
6412
|
+
} else if (t.startsWith("{") && t.endsWith("}") || t.startsWith("[") && t.endsWith("]") || t.startsWith('"') && t.endsWith('"')) {
|
|
6413
|
+
try {
|
|
6414
|
+
parsed = JSON.parse(t);
|
|
6415
|
+
} catch {
|
|
6416
|
+
parsed = value;
|
|
6417
|
+
}
|
|
6418
|
+
}
|
|
6419
|
+
}
|
|
6420
|
+
return { key: String(key), value: parsed };
|
|
6421
|
+
}
|
|
6422
|
+
/**
|
|
6423
|
+
* Enqueue one or many setRuntimeParam tasks. Prefer this over a bare
|
|
6424
|
+
* `enqueueTask` when broadcasting to a service group.
|
|
6425
|
+
*
|
|
6426
|
+
* @param {object} context
|
|
6427
|
+
* @param {Record<string, unknown>} [overrides]
|
|
6428
|
+
* @returns {Promise<{ ids: string[], targets: string[] }>}
|
|
6429
|
+
*/
|
|
6430
|
+
static async enqueue(context, overrides = {}) {
|
|
6431
|
+
const payload = await this.resolveParams(context, { ...overrides, name: "setRuntimeParam" });
|
|
6432
|
+
const queueName = payload.queueName ?? "tasks";
|
|
6433
|
+
if (payload.serviceName) {
|
|
6434
|
+
const id = await enqueueTask(context, payload);
|
|
6435
|
+
return { ids: [id], targets: [payload.serviceName] };
|
|
6436
|
+
}
|
|
6437
|
+
const group = String(payload.serviceGroup || "").trim();
|
|
6438
|
+
if (!group) {
|
|
6439
|
+
throw new ParamError("setRuntimeParam.enqueue: serviceGroup required for broadcast");
|
|
6440
|
+
}
|
|
6441
|
+
const alive = await listServicesRegistry(context, {
|
|
6442
|
+
queueName,
|
|
6443
|
+
serviceGroup: group,
|
|
6444
|
+
staleMs: overrides.staleMs ?? 45e3
|
|
6445
|
+
});
|
|
6446
|
+
if (!alive.length) {
|
|
6447
|
+
throw new ParamError(
|
|
6448
|
+
`setRuntimeParam: no alive services in group="${group}" queue="${queueName}"`
|
|
6449
|
+
);
|
|
6450
|
+
}
|
|
6451
|
+
const ids = [];
|
|
6452
|
+
const targets = [];
|
|
6453
|
+
for (const reg of alive) {
|
|
6454
|
+
const id = await enqueueTask(context, {
|
|
6455
|
+
...payload,
|
|
6456
|
+
serviceGroup: group,
|
|
6457
|
+
serviceName: reg.service_name,
|
|
6458
|
+
serverName: reg.server_name ?? null,
|
|
6459
|
+
instanceNumber: reg.instance_number ?? null
|
|
6460
|
+
});
|
|
6461
|
+
ids.push(id);
|
|
6462
|
+
targets.push(reg.service_name);
|
|
6463
|
+
}
|
|
6464
|
+
context.logger?.info?.(
|
|
6465
|
+
`[setRuntimeParam] broadcast to ${targets.length} instance(s) in group=${group}: ${targets.join(", ")}`
|
|
6466
|
+
);
|
|
6467
|
+
return { ids, targets };
|
|
6468
|
+
}
|
|
6469
|
+
/**
|
|
6470
|
+
* @returns {Promise<{ success: true, results: object }>}
|
|
6471
|
+
*/
|
|
6472
|
+
async run() {
|
|
6473
|
+
const params = this.task?.params ?? {};
|
|
6474
|
+
let changes;
|
|
6475
|
+
if (params.patch && typeof params.patch === "object") {
|
|
6476
|
+
changes = await applyRuntimePatch(this.context, params.patch);
|
|
6477
|
+
} else {
|
|
6478
|
+
changes = [await applyRuntimeParam(this.context, params.key, params.value)];
|
|
6479
|
+
}
|
|
6480
|
+
const summary = changes.map((c) => `${c.key}: ${JSON.stringify(c.previous)} \u2192 ${JSON.stringify(c.next)}`);
|
|
6481
|
+
this.context.logger.warn?.(
|
|
6482
|
+
`[TaskSetRuntimeParam] applied on ${this.context.servicesRegistry?.serviceName ?? "runner"}: ${summary.join("; ")}`
|
|
6483
|
+
);
|
|
6484
|
+
return {
|
|
6485
|
+
success: true,
|
|
6486
|
+
results: {
|
|
6487
|
+
runtimeParamApplied: true,
|
|
6488
|
+
changes,
|
|
6489
|
+
runtime: { ...this.context.tasksRuntime ?? {} }
|
|
6490
|
+
}
|
|
6491
|
+
};
|
|
6492
|
+
}
|
|
6493
|
+
};
|
|
6494
|
+
|
|
6145
6495
|
// src/tasks/TasksRegistry.js
|
|
6146
6496
|
var TasksRegistry = class _TasksRegistry {
|
|
6147
6497
|
/**
|
|
@@ -6160,7 +6510,7 @@ var TasksRegistry = class _TasksRegistry {
|
|
|
6160
6510
|
* @returns {TasksRegistry}
|
|
6161
6511
|
*/
|
|
6162
6512
|
static withCoreTasks() {
|
|
6163
|
-
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);
|
|
6513
|
+
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);
|
|
6164
6514
|
}
|
|
6165
6515
|
/**
|
|
6166
6516
|
* Register a single task class under a name. Overwrites any previous entry.
|
|
@@ -6489,18 +6839,23 @@ async function claimNextRunnableTask(context, tasksTable, serviceGroup, registry
|
|
|
6489
6839
|
async function runTasksLoop(context, options) {
|
|
6490
6840
|
const queueName = options.queueName ?? "tasks";
|
|
6491
6841
|
const target = options.target;
|
|
6492
|
-
const pollMs = options.pollMs ?? 1e3;
|
|
6493
|
-
const claimJitterMs = options.claimJitterMs ?? 0;
|
|
6494
|
-
const maxParallel = options.maxParallel ?? 32;
|
|
6495
|
-
const scanLimit = options.scanLimit ?? 100;
|
|
6496
6842
|
const allowedTasks = normalizeAllowedTasks(options.allowedTasks);
|
|
6497
6843
|
const registry = normalizeRegistry(options.registry);
|
|
6498
6844
|
const { tasksTable, historyTable } = queueToTableNames(queueName);
|
|
6499
6845
|
if (!target) throw new Error("runTasksLoop: target is required");
|
|
6500
6846
|
context.tasksQueueName = queueName;
|
|
6847
|
+
ensureTasksRuntime(context, {
|
|
6848
|
+
maxParallel: options.maxParallel ?? 32,
|
|
6849
|
+
pollMs: options.pollMs ?? 1e3,
|
|
6850
|
+
claimJitterMs: options.claimJitterMs ?? 0,
|
|
6851
|
+
scanLimit: options.scanLimit ?? 100
|
|
6852
|
+
});
|
|
6853
|
+
if (typeof options.onRuntimeParam === "function") {
|
|
6854
|
+
context.tasksRuntimeOnParam = options.onRuntimeParam;
|
|
6855
|
+
}
|
|
6501
6856
|
const runningPromises = /* @__PURE__ */ new Set();
|
|
6502
6857
|
const runningTaskInstances = /* @__PURE__ */ new Map();
|
|
6503
|
-
let
|
|
6858
|
+
let runningControlPromise = null;
|
|
6504
6859
|
let stopRequested = false;
|
|
6505
6860
|
let stopAllowanceMs = 5e3;
|
|
6506
6861
|
context.tasksRunnerStop = false;
|
|
@@ -6511,9 +6866,16 @@ async function runTasksLoop(context, options) {
|
|
|
6511
6866
|
if (hbGroup) {
|
|
6512
6867
|
const hbIntervalMs = options.runnerHeartbeatIntervalMs ?? 1e4;
|
|
6513
6868
|
const staleMs = options.runnerHeartbeatStaleMs ?? 45e3;
|
|
6869
|
+
const loop0 = readLoopRuntime(context);
|
|
6514
6870
|
const defaultMeta = {
|
|
6515
6871
|
component: "tasks-runner",
|
|
6516
|
-
allowedTasks: allowedTasks?.length ? allowedTasks.join(",") : "all"
|
|
6872
|
+
allowedTasks: allowedTasks?.length ? allowedTasks.join(",") : "all",
|
|
6873
|
+
runtime: {
|
|
6874
|
+
maxParallel: loop0.maxParallel,
|
|
6875
|
+
pollMs: loop0.pollMs,
|
|
6876
|
+
claimJitterMs: loop0.claimJitterMs,
|
|
6877
|
+
scanLimit: loop0.scanLimit
|
|
6878
|
+
}
|
|
6517
6879
|
};
|
|
6518
6880
|
registryReg = await registerInServicesRegistry(context, {
|
|
6519
6881
|
queueName,
|
|
@@ -6526,6 +6888,7 @@ async function runTasksLoop(context, options) {
|
|
|
6526
6888
|
enforceMaxInstances: options.runnerEnforceMaxInstances ?? true,
|
|
6527
6889
|
metadata: options.runnerMetadata ?? defaultMeta
|
|
6528
6890
|
});
|
|
6891
|
+
context.servicesRegistry = registryReg;
|
|
6529
6892
|
runnerIdentity = {
|
|
6530
6893
|
service_name: registryReg.serviceName,
|
|
6531
6894
|
server_name: os3.hostname(),
|
|
@@ -6539,22 +6902,23 @@ async function runTasksLoop(context, options) {
|
|
|
6539
6902
|
}
|
|
6540
6903
|
try {
|
|
6541
6904
|
while (!context.isStop() && !stopRequested && context.tasksRunnerStop !== true) {
|
|
6542
|
-
|
|
6543
|
-
|
|
6905
|
+
const { maxParallel, pollMs, claimJitterMs, scanLimit } = readLoopRuntime(context);
|
|
6906
|
+
if (!runningControlPromise) {
|
|
6907
|
+
const claimedControlTask = await claimNextRunnableTask(
|
|
6544
6908
|
context,
|
|
6545
6909
|
tasksTable,
|
|
6546
6910
|
target,
|
|
6547
6911
|
registry,
|
|
6548
6912
|
10,
|
|
6549
|
-
|
|
6913
|
+
controlLaneTaskNames(),
|
|
6550
6914
|
runnerIdentity
|
|
6551
6915
|
);
|
|
6552
|
-
if (
|
|
6553
|
-
|
|
6916
|
+
if (claimedControlTask) {
|
|
6917
|
+
runningControlPromise = executeClaimedTask(
|
|
6554
6918
|
context,
|
|
6555
6919
|
tasksTable,
|
|
6556
6920
|
historyTable,
|
|
6557
|
-
|
|
6921
|
+
claimedControlTask,
|
|
6558
6922
|
registry,
|
|
6559
6923
|
runningTaskInstances
|
|
6560
6924
|
).then(async (outcome) => {
|
|
@@ -6565,7 +6929,7 @@ async function runTasksLoop(context, options) {
|
|
|
6565
6929
|
await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
|
|
6566
6930
|
}
|
|
6567
6931
|
}).finally(() => {
|
|
6568
|
-
|
|
6932
|
+
runningControlPromise = null;
|
|
6569
6933
|
});
|
|
6570
6934
|
}
|
|
6571
6935
|
}
|
|
@@ -6596,8 +6960,8 @@ async function runTasksLoop(context, options) {
|
|
|
6596
6960
|
runningPromises.add(p);
|
|
6597
6961
|
}
|
|
6598
6962
|
const wakePromises = [...runningPromises];
|
|
6599
|
-
if (
|
|
6600
|
-
wakePromises.push(
|
|
6963
|
+
if (runningControlPromise) {
|
|
6964
|
+
wakePromises.push(runningControlPromise);
|
|
6601
6965
|
}
|
|
6602
6966
|
if (wakePromises.length === 0) {
|
|
6603
6967
|
await sleepMs(pollMs);
|