@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.cjs
CHANGED
|
@@ -2703,6 +2703,9 @@ async function init(flow2, opts = {}) {
|
|
|
2703
2703
|
if (context) {
|
|
2704
2704
|
await runRegisteredCleanups(context);
|
|
2705
2705
|
}
|
|
2706
|
+
if (process.exitCode && process.exitCode !== 0) {
|
|
2707
|
+
process.exit(process.exitCode);
|
|
2708
|
+
}
|
|
2706
2709
|
}
|
|
2707
2710
|
}
|
|
2708
2711
|
|
|
@@ -3982,6 +3985,51 @@ async function dropLegacyTaskNameColumn(db, tableNames, { dryRun, log, label })
|
|
|
3982
3985
|
}
|
|
3983
3986
|
return actions;
|
|
3984
3987
|
}
|
|
3988
|
+
async function enqueueTask(context, options) {
|
|
3989
|
+
const db = getDb(context);
|
|
3990
|
+
const queueName = options.queueName ?? "tasks";
|
|
3991
|
+
const { tasksTable } = queueToTableNames(queueName);
|
|
3992
|
+
const id = (0, import_node_crypto.randomUUID)();
|
|
3993
|
+
const name = options.name ?? options.task;
|
|
3994
|
+
if (!name) {
|
|
3995
|
+
throw new Error("enqueueTask: name (or task) is required");
|
|
3996
|
+
}
|
|
3997
|
+
const schedule = options.schedule?.trim() ? options.schedule : null;
|
|
3998
|
+
let nextRunAt = null;
|
|
3999
|
+
if (options.nextRunAt !== void 0) {
|
|
4000
|
+
nextRunAt = options.nextRunAt == null ? null : new Date(options.nextRunAt);
|
|
4001
|
+
} else if (schedule) {
|
|
4002
|
+
nextRunAt = nextTimeMatch(schedule, /* @__PURE__ */ new Date());
|
|
4003
|
+
}
|
|
4004
|
+
const row = {
|
|
4005
|
+
id,
|
|
4006
|
+
name,
|
|
4007
|
+
params: toJsonColumn(options.params ?? null),
|
|
4008
|
+
opid: options.opid ?? null,
|
|
4009
|
+
priority: options.priority ?? 50,
|
|
4010
|
+
schedule,
|
|
4011
|
+
next_run_at: nextRunAt,
|
|
4012
|
+
service_group: options.serviceGroup ?? null,
|
|
4013
|
+
instance_number: options.instanceNumber ?? null,
|
|
4014
|
+
service_name: options.serviceName ?? null,
|
|
4015
|
+
server_name: options.serverName ?? null,
|
|
4016
|
+
status: "idle",
|
|
4017
|
+
status_changed_at: db.fn.now()
|
|
4018
|
+
};
|
|
4019
|
+
if (await tableHasLegacyTaskColumn(db, tasksTable)) {
|
|
4020
|
+
row.task = name;
|
|
4021
|
+
}
|
|
4022
|
+
await db(tasksTable).insert(row);
|
|
4023
|
+
return id;
|
|
4024
|
+
}
|
|
4025
|
+
var legacyTaskColumnCache = /* @__PURE__ */ new Map();
|
|
4026
|
+
async function tableHasLegacyTaskColumn(db, tableName) {
|
|
4027
|
+
const key = `${db?.config?.name ?? "db"}:${tableName}`;
|
|
4028
|
+
if (!legacyTaskColumnCache.has(key)) {
|
|
4029
|
+
legacyTaskColumnCache.set(key, await db.schema.hasColumn(tableName, "task"));
|
|
4030
|
+
}
|
|
4031
|
+
return legacyTaskColumnCache.get(key);
|
|
4032
|
+
}
|
|
3985
4033
|
async function updateTaskProgress(context, tasksTable, taskId, progress) {
|
|
3986
4034
|
const db = getDb(context);
|
|
3987
4035
|
await db(tasksTable).where({ id: taskId }).update({
|
|
@@ -3997,6 +4045,19 @@ function getDb2(context) {
|
|
|
3997
4045
|
}
|
|
3998
4046
|
return db;
|
|
3999
4047
|
}
|
|
4048
|
+
function parseMetadataColumn(value) {
|
|
4049
|
+
if (!value) return {};
|
|
4050
|
+
if (typeof value === "object" && !Array.isArray(value)) return value;
|
|
4051
|
+
if (typeof value === "string") {
|
|
4052
|
+
try {
|
|
4053
|
+
const p = JSON.parse(value);
|
|
4054
|
+
return p && typeof p === "object" && !Array.isArray(value) ? p : {};
|
|
4055
|
+
} catch {
|
|
4056
|
+
return {};
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
return {};
|
|
4060
|
+
}
|
|
4000
4061
|
var DEFAULT_GROUP_MAX_INSTANCES = {
|
|
4001
4062
|
intake: 1,
|
|
4002
4063
|
harvest: 1,
|
|
@@ -4195,11 +4256,33 @@ async function touchServicesRegistry(context, registration) {
|
|
|
4195
4256
|
pid
|
|
4196
4257
|
});
|
|
4197
4258
|
}
|
|
4259
|
+
async function updateServicesRegistryMetadata(context, registration, patch) {
|
|
4260
|
+
const db = getDb2(context);
|
|
4261
|
+
const row = await db(registration.registryTable).where({ id: registration.rowId }).first();
|
|
4262
|
+
const prev = parseMetadataColumn(row?.metadata);
|
|
4263
|
+
const merged = { ...prev, ...patch };
|
|
4264
|
+
await db(registration.registryTable).where({ id: registration.rowId }).update({
|
|
4265
|
+
metadata: toJsonColumn(merged),
|
|
4266
|
+
last_seen_at: db.fn.now()
|
|
4267
|
+
});
|
|
4268
|
+
context.logger.info?.(`[services-registry] metadata updated for ${registration.serviceName}`);
|
|
4269
|
+
}
|
|
4198
4270
|
async function unregisterServicesRegistry(context, registration) {
|
|
4199
4271
|
const db = getDb2(context);
|
|
4200
4272
|
await db(registration.registryTable).where({ id: registration.rowId }).delete();
|
|
4201
4273
|
context.logger.info?.(`[services-registry] unregistered name=${registration.serviceName} id=${registration.rowId}`);
|
|
4202
4274
|
}
|
|
4275
|
+
async function listServicesRegistry(context, options = { queueName: "tasks" }) {
|
|
4276
|
+
const db = getDb2(context);
|
|
4277
|
+
const staleMs = options.staleMs ?? 6e4;
|
|
4278
|
+
const cutoff = new Date(Date.now() - staleMs);
|
|
4279
|
+
const table = queueToTableNames(options.queueName).registryTable;
|
|
4280
|
+
let q = db(table).where("last_seen_at", ">", cutoff).orderBy([{ column: "service_group", order: "asc" }, { column: "service_name", order: "asc" }]);
|
|
4281
|
+
if (options.serviceGroup?.trim()) {
|
|
4282
|
+
q = q.where({ service_group: options.serviceGroup.trim() });
|
|
4283
|
+
}
|
|
4284
|
+
return await q;
|
|
4285
|
+
}
|
|
4203
4286
|
|
|
4204
4287
|
// src/tasks/taskLogs.js
|
|
4205
4288
|
var import_node_path = __toESM(require("path"), 1);
|
|
@@ -6158,6 +6241,273 @@ var TaskGetLogs = class extends AbstractTask {
|
|
|
6158
6241
|
}
|
|
6159
6242
|
};
|
|
6160
6243
|
|
|
6244
|
+
// src/tasks/runtimeParams.js
|
|
6245
|
+
var LOOP_RUNTIME_KEYS = ["maxParallel", "pollMs", "claimJitterMs", "scanLimit"];
|
|
6246
|
+
var LOGGER_RUNTIME_KEYS = [
|
|
6247
|
+
"levels",
|
|
6248
|
+
"silent",
|
|
6249
|
+
"showLevel",
|
|
6250
|
+
"timestamp",
|
|
6251
|
+
"mode",
|
|
6252
|
+
"route",
|
|
6253
|
+
"prefix",
|
|
6254
|
+
"progressWithTimes",
|
|
6255
|
+
"progressThrottleMs"
|
|
6256
|
+
];
|
|
6257
|
+
var CONTROL_LANE_TASK_NAMES = ["stopRunner", "stop", "setRuntimeParam", "setRunnerParam"];
|
|
6258
|
+
function controlLaneTaskNames() {
|
|
6259
|
+
return [...CONTROL_LANE_TASK_NAMES];
|
|
6260
|
+
}
|
|
6261
|
+
function asPositiveInt(value, key, { min = 1 } = {}) {
|
|
6262
|
+
const n = Number(value);
|
|
6263
|
+
if (!Number.isFinite(n) || n < min) {
|
|
6264
|
+
throw new ParamError(
|
|
6265
|
+
`setRuntimeParam: ${key} must be a number >= ${min} (got ${JSON.stringify(value)})`
|
|
6266
|
+
);
|
|
6267
|
+
}
|
|
6268
|
+
return Math.floor(n);
|
|
6269
|
+
}
|
|
6270
|
+
function coerceRuntimeValue(key, value) {
|
|
6271
|
+
switch (key) {
|
|
6272
|
+
case "maxParallel":
|
|
6273
|
+
return asPositiveInt(value, key, { min: 1 });
|
|
6274
|
+
case "pollMs":
|
|
6275
|
+
return asPositiveInt(value, key, { min: 50 });
|
|
6276
|
+
case "claimJitterMs":
|
|
6277
|
+
return asPositiveInt(value, key, { min: 0 });
|
|
6278
|
+
case "scanLimit":
|
|
6279
|
+
return asPositiveInt(value, key, { min: 1 });
|
|
6280
|
+
case "silent":
|
|
6281
|
+
case "showLevel":
|
|
6282
|
+
case "timestamp":
|
|
6283
|
+
case "progressWithTimes":
|
|
6284
|
+
if (typeof value === "boolean") return value;
|
|
6285
|
+
if (value === "true" || value === "1") return true;
|
|
6286
|
+
if (value === "false" || value === "0") return false;
|
|
6287
|
+
throw new ParamError(
|
|
6288
|
+
`setRuntimeParam: ${key} must be boolean (got ${JSON.stringify(value)})`
|
|
6289
|
+
);
|
|
6290
|
+
case "progressThrottleMs":
|
|
6291
|
+
return asPositiveInt(value, key, { min: 0 });
|
|
6292
|
+
case "levels":
|
|
6293
|
+
case "mode":
|
|
6294
|
+
case "route":
|
|
6295
|
+
case "prefix":
|
|
6296
|
+
return value;
|
|
6297
|
+
default:
|
|
6298
|
+
return value;
|
|
6299
|
+
}
|
|
6300
|
+
}
|
|
6301
|
+
function ensureTasksRuntime(context, seed = {}) {
|
|
6302
|
+
if (!context.tasksRuntime || typeof context.tasksRuntime !== "object") {
|
|
6303
|
+
context.tasksRuntime = {};
|
|
6304
|
+
}
|
|
6305
|
+
const rt = context.tasksRuntime;
|
|
6306
|
+
if (rt.maxParallel === void 0) rt.maxParallel = seed.maxParallel ?? 32;
|
|
6307
|
+
if (rt.pollMs === void 0) rt.pollMs = seed.pollMs ?? 1e3;
|
|
6308
|
+
if (rt.claimJitterMs === void 0) rt.claimJitterMs = seed.claimJitterMs ?? 0;
|
|
6309
|
+
if (rt.scanLimit === void 0) rt.scanLimit = seed.scanLimit ?? 100;
|
|
6310
|
+
return rt;
|
|
6311
|
+
}
|
|
6312
|
+
async function applyRuntimeParam(context, key, value) {
|
|
6313
|
+
const k = String(key ?? "").trim();
|
|
6314
|
+
if (!k) throw new ParamError("setRuntimeParam: key is required");
|
|
6315
|
+
const runtime = ensureTasksRuntime(context);
|
|
6316
|
+
const next = coerceRuntimeValue(k, value);
|
|
6317
|
+
const previous = runtime[k];
|
|
6318
|
+
const applied = [];
|
|
6319
|
+
runtime[k] = next;
|
|
6320
|
+
applied.push("tasksRuntime");
|
|
6321
|
+
if (LOGGER_RUNTIME_KEYS.includes(k) && context.logger?.configure) {
|
|
6322
|
+
context.logger.configure({ [k]: next });
|
|
6323
|
+
applied.push("logger");
|
|
6324
|
+
}
|
|
6325
|
+
const hook = context.tasksRuntimeOnParam;
|
|
6326
|
+
if (typeof hook === "function") {
|
|
6327
|
+
await hook(k, next, runtime, context);
|
|
6328
|
+
applied.push("onRuntimeParam");
|
|
6329
|
+
}
|
|
6330
|
+
const reg = context.servicesRegistry;
|
|
6331
|
+
if (reg?.rowId && reg?.registryTable) {
|
|
6332
|
+
try {
|
|
6333
|
+
const loopSnapshot = {};
|
|
6334
|
+
for (const lk of LOOP_RUNTIME_KEYS) {
|
|
6335
|
+
if (runtime[lk] !== void 0) loopSnapshot[lk] = runtime[lk];
|
|
6336
|
+
}
|
|
6337
|
+
await updateServicesRegistryMetadata(context, reg, {
|
|
6338
|
+
runtime: loopSnapshot,
|
|
6339
|
+
runtimeUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6340
|
+
});
|
|
6341
|
+
applied.push("servicesRegistry");
|
|
6342
|
+
} catch (err) {
|
|
6343
|
+
context.logger?.warn?.(
|
|
6344
|
+
`[setRuntimeParam] registry metadata update failed: ${err?.message ?? String(err)}`
|
|
6345
|
+
);
|
|
6346
|
+
}
|
|
6347
|
+
}
|
|
6348
|
+
return { key: k, previous, next, applied };
|
|
6349
|
+
}
|
|
6350
|
+
async function applyRuntimePatch(context, patch) {
|
|
6351
|
+
if (!patch || typeof patch !== "object" || Array.isArray(patch)) {
|
|
6352
|
+
throw new ParamError("setRuntimeParam: patch must be a plain object");
|
|
6353
|
+
}
|
|
6354
|
+
const entries = Object.entries(patch);
|
|
6355
|
+
if (entries.length === 0) {
|
|
6356
|
+
throw new ParamError("setRuntimeParam: patch is empty");
|
|
6357
|
+
}
|
|
6358
|
+
const out = [];
|
|
6359
|
+
for (const [key, value] of entries) {
|
|
6360
|
+
out.push(await applyRuntimeParam(context, key, value));
|
|
6361
|
+
}
|
|
6362
|
+
return out;
|
|
6363
|
+
}
|
|
6364
|
+
function readLoopRuntime(context) {
|
|
6365
|
+
const rt = ensureTasksRuntime(context);
|
|
6366
|
+
return {
|
|
6367
|
+
maxParallel: Math.max(1, Number(rt.maxParallel) || 1),
|
|
6368
|
+
pollMs: Math.max(50, Number(rt.pollMs) || 1e3),
|
|
6369
|
+
claimJitterMs: Math.max(0, Number(rt.claimJitterMs) || 0),
|
|
6370
|
+
scanLimit: Math.max(1, Number(rt.scanLimit) || 100)
|
|
6371
|
+
};
|
|
6372
|
+
}
|
|
6373
|
+
|
|
6374
|
+
// src/tasks/coreTasks/TaskSetRuntimeParam.js
|
|
6375
|
+
var TaskSetRuntimeParam = class extends AbstractTask {
|
|
6376
|
+
static defaultWaitForResult = true;
|
|
6377
|
+
/**
|
|
6378
|
+
* @param {object} context
|
|
6379
|
+
* @param {Record<string, unknown>} [overrides]
|
|
6380
|
+
* @returns {Promise<object>}
|
|
6381
|
+
*/
|
|
6382
|
+
static async resolveParams(context, overrides = {}) {
|
|
6383
|
+
const main = await super.resolveParams(context, overrides);
|
|
6384
|
+
if (!main.serviceName && !main.serviceGroup) {
|
|
6385
|
+
throw new ParamError(
|
|
6386
|
+
"setRuntimeParam requires --serviceName (one instance) or --serviceGroup (broadcast to alive instances)"
|
|
6387
|
+
);
|
|
6388
|
+
}
|
|
6389
|
+
return main;
|
|
6390
|
+
}
|
|
6391
|
+
/**
|
|
6392
|
+
* @param {object} context
|
|
6393
|
+
* @param {Record<string, unknown>} [overrides]
|
|
6394
|
+
* @returns {Promise<{ key?: string, value?: unknown, patch?: Record<string, unknown> }>}
|
|
6395
|
+
*/
|
|
6396
|
+
static async resolveCustomParams(context, overrides = {}) {
|
|
6397
|
+
const merged = AbstractTask._mergeTypedParams(
|
|
6398
|
+
context,
|
|
6399
|
+
"task-set-runtime-param",
|
|
6400
|
+
{
|
|
6401
|
+
paramKey: "string",
|
|
6402
|
+
paramValue: "string",
|
|
6403
|
+
key: "string",
|
|
6404
|
+
value: "string"
|
|
6405
|
+
},
|
|
6406
|
+
overrides
|
|
6407
|
+
);
|
|
6408
|
+
if (merged.patch && typeof merged.patch === "object" && !Array.isArray(merged.patch)) {
|
|
6409
|
+
if (Object.keys(merged.patch).length === 0) {
|
|
6410
|
+
throw new ParamError("setRuntimeParam: patch is empty");
|
|
6411
|
+
}
|
|
6412
|
+
return { patch: { ...merged.patch } };
|
|
6413
|
+
}
|
|
6414
|
+
const key = merged.paramKey || merged.key;
|
|
6415
|
+
const value = merged.paramValue !== void 0 ? merged.paramValue : merged.value;
|
|
6416
|
+
if (!key) {
|
|
6417
|
+
throw new ParamError(
|
|
6418
|
+
`setRuntimeParam requires --paramKey/--paramValue, or --paramsJson '{"key":"maxParallel","value":16}' / '{"patch":{...}}'`
|
|
6419
|
+
);
|
|
6420
|
+
}
|
|
6421
|
+
let parsed = value;
|
|
6422
|
+
if (typeof value === "string") {
|
|
6423
|
+
const t = value.trim();
|
|
6424
|
+
if (t === "true") parsed = true;
|
|
6425
|
+
else if (t === "false") parsed = false;
|
|
6426
|
+
else if (t !== "" && !Number.isNaN(Number(t)) && /^-?\d+(\.\d+)?$/.test(t)) {
|
|
6427
|
+
parsed = Number(t);
|
|
6428
|
+
} else if (t.startsWith("{") && t.endsWith("}") || t.startsWith("[") && t.endsWith("]") || t.startsWith('"') && t.endsWith('"')) {
|
|
6429
|
+
try {
|
|
6430
|
+
parsed = JSON.parse(t);
|
|
6431
|
+
} catch {
|
|
6432
|
+
parsed = value;
|
|
6433
|
+
}
|
|
6434
|
+
}
|
|
6435
|
+
}
|
|
6436
|
+
return { key: String(key), value: parsed };
|
|
6437
|
+
}
|
|
6438
|
+
/**
|
|
6439
|
+
* Enqueue one or many setRuntimeParam tasks. Prefer this over a bare
|
|
6440
|
+
* `enqueueTask` when broadcasting to a service group.
|
|
6441
|
+
*
|
|
6442
|
+
* @param {object} context
|
|
6443
|
+
* @param {Record<string, unknown>} [overrides]
|
|
6444
|
+
* @returns {Promise<{ ids: string[], targets: string[] }>}
|
|
6445
|
+
*/
|
|
6446
|
+
static async enqueue(context, overrides = {}) {
|
|
6447
|
+
const payload = await this.resolveParams(context, { ...overrides, name: "setRuntimeParam" });
|
|
6448
|
+
const queueName = payload.queueName ?? "tasks";
|
|
6449
|
+
if (payload.serviceName) {
|
|
6450
|
+
const id = await enqueueTask(context, payload);
|
|
6451
|
+
return { ids: [id], targets: [payload.serviceName] };
|
|
6452
|
+
}
|
|
6453
|
+
const group = String(payload.serviceGroup || "").trim();
|
|
6454
|
+
if (!group) {
|
|
6455
|
+
throw new ParamError("setRuntimeParam.enqueue: serviceGroup required for broadcast");
|
|
6456
|
+
}
|
|
6457
|
+
const alive = await listServicesRegistry(context, {
|
|
6458
|
+
queueName,
|
|
6459
|
+
serviceGroup: group,
|
|
6460
|
+
staleMs: overrides.staleMs ?? 45e3
|
|
6461
|
+
});
|
|
6462
|
+
if (!alive.length) {
|
|
6463
|
+
throw new ParamError(
|
|
6464
|
+
`setRuntimeParam: no alive services in group="${group}" queue="${queueName}"`
|
|
6465
|
+
);
|
|
6466
|
+
}
|
|
6467
|
+
const ids = [];
|
|
6468
|
+
const targets = [];
|
|
6469
|
+
for (const reg of alive) {
|
|
6470
|
+
const id = await enqueueTask(context, {
|
|
6471
|
+
...payload,
|
|
6472
|
+
serviceGroup: group,
|
|
6473
|
+
serviceName: reg.service_name,
|
|
6474
|
+
serverName: reg.server_name ?? null,
|
|
6475
|
+
instanceNumber: reg.instance_number ?? null
|
|
6476
|
+
});
|
|
6477
|
+
ids.push(id);
|
|
6478
|
+
targets.push(reg.service_name);
|
|
6479
|
+
}
|
|
6480
|
+
context.logger?.info?.(
|
|
6481
|
+
`[setRuntimeParam] broadcast to ${targets.length} instance(s) in group=${group}: ${targets.join(", ")}`
|
|
6482
|
+
);
|
|
6483
|
+
return { ids, targets };
|
|
6484
|
+
}
|
|
6485
|
+
/**
|
|
6486
|
+
* @returns {Promise<{ success: true, results: object }>}
|
|
6487
|
+
*/
|
|
6488
|
+
async run() {
|
|
6489
|
+
const params = this.task?.params ?? {};
|
|
6490
|
+
let changes;
|
|
6491
|
+
if (params.patch && typeof params.patch === "object") {
|
|
6492
|
+
changes = await applyRuntimePatch(this.context, params.patch);
|
|
6493
|
+
} else {
|
|
6494
|
+
changes = [await applyRuntimeParam(this.context, params.key, params.value)];
|
|
6495
|
+
}
|
|
6496
|
+
const summary = changes.map((c) => `${c.key}: ${JSON.stringify(c.previous)} \u2192 ${JSON.stringify(c.next)}`);
|
|
6497
|
+
this.context.logger.warn?.(
|
|
6498
|
+
`[TaskSetRuntimeParam] applied on ${this.context.servicesRegistry?.serviceName ?? "runner"}: ${summary.join("; ")}`
|
|
6499
|
+
);
|
|
6500
|
+
return {
|
|
6501
|
+
success: true,
|
|
6502
|
+
results: {
|
|
6503
|
+
runtimeParamApplied: true,
|
|
6504
|
+
changes,
|
|
6505
|
+
runtime: { ...this.context.tasksRuntime ?? {} }
|
|
6506
|
+
}
|
|
6507
|
+
};
|
|
6508
|
+
}
|
|
6509
|
+
};
|
|
6510
|
+
|
|
6161
6511
|
// src/tasks/TasksRegistry.js
|
|
6162
6512
|
var TasksRegistry = class _TasksRegistry {
|
|
6163
6513
|
/**
|
|
@@ -6176,7 +6526,7 @@ var TasksRegistry = class _TasksRegistry {
|
|
|
6176
6526
|
* @returns {TasksRegistry}
|
|
6177
6527
|
*/
|
|
6178
6528
|
static withCoreTasks() {
|
|
6179
|
-
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);
|
|
6529
|
+
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);
|
|
6180
6530
|
}
|
|
6181
6531
|
/**
|
|
6182
6532
|
* Register a single task class under a name. Overwrites any previous entry.
|
|
@@ -6505,18 +6855,23 @@ async function claimNextRunnableTask(context, tasksTable, serviceGroup, registry
|
|
|
6505
6855
|
async function runTasksLoop(context, options) {
|
|
6506
6856
|
const queueName = options.queueName ?? "tasks";
|
|
6507
6857
|
const target = options.target;
|
|
6508
|
-
const pollMs = options.pollMs ?? 1e3;
|
|
6509
|
-
const claimJitterMs = options.claimJitterMs ?? 0;
|
|
6510
|
-
const maxParallel = options.maxParallel ?? 32;
|
|
6511
|
-
const scanLimit = options.scanLimit ?? 100;
|
|
6512
6858
|
const allowedTasks = normalizeAllowedTasks(options.allowedTasks);
|
|
6513
6859
|
const registry = normalizeRegistry(options.registry);
|
|
6514
6860
|
const { tasksTable, historyTable } = queueToTableNames(queueName);
|
|
6515
6861
|
if (!target) throw new Error("runTasksLoop: target is required");
|
|
6516
6862
|
context.tasksQueueName = queueName;
|
|
6863
|
+
ensureTasksRuntime(context, {
|
|
6864
|
+
maxParallel: options.maxParallel ?? 32,
|
|
6865
|
+
pollMs: options.pollMs ?? 1e3,
|
|
6866
|
+
claimJitterMs: options.claimJitterMs ?? 0,
|
|
6867
|
+
scanLimit: options.scanLimit ?? 100
|
|
6868
|
+
});
|
|
6869
|
+
if (typeof options.onRuntimeParam === "function") {
|
|
6870
|
+
context.tasksRuntimeOnParam = options.onRuntimeParam;
|
|
6871
|
+
}
|
|
6517
6872
|
const runningPromises = /* @__PURE__ */ new Set();
|
|
6518
6873
|
const runningTaskInstances = /* @__PURE__ */ new Map();
|
|
6519
|
-
let
|
|
6874
|
+
let runningControlPromise = null;
|
|
6520
6875
|
let stopRequested = false;
|
|
6521
6876
|
let stopAllowanceMs = 5e3;
|
|
6522
6877
|
context.tasksRunnerStop = false;
|
|
@@ -6527,9 +6882,16 @@ async function runTasksLoop(context, options) {
|
|
|
6527
6882
|
if (hbGroup) {
|
|
6528
6883
|
const hbIntervalMs = options.runnerHeartbeatIntervalMs ?? 1e4;
|
|
6529
6884
|
const staleMs = options.runnerHeartbeatStaleMs ?? 45e3;
|
|
6885
|
+
const loop0 = readLoopRuntime(context);
|
|
6530
6886
|
const defaultMeta = {
|
|
6531
6887
|
component: "tasks-runner",
|
|
6532
|
-
allowedTasks: allowedTasks?.length ? allowedTasks.join(",") : "all"
|
|
6888
|
+
allowedTasks: allowedTasks?.length ? allowedTasks.join(",") : "all",
|
|
6889
|
+
runtime: {
|
|
6890
|
+
maxParallel: loop0.maxParallel,
|
|
6891
|
+
pollMs: loop0.pollMs,
|
|
6892
|
+
claimJitterMs: loop0.claimJitterMs,
|
|
6893
|
+
scanLimit: loop0.scanLimit
|
|
6894
|
+
}
|
|
6533
6895
|
};
|
|
6534
6896
|
registryReg = await registerInServicesRegistry(context, {
|
|
6535
6897
|
queueName,
|
|
@@ -6542,6 +6904,7 @@ async function runTasksLoop(context, options) {
|
|
|
6542
6904
|
enforceMaxInstances: options.runnerEnforceMaxInstances ?? true,
|
|
6543
6905
|
metadata: options.runnerMetadata ?? defaultMeta
|
|
6544
6906
|
});
|
|
6907
|
+
context.servicesRegistry = registryReg;
|
|
6545
6908
|
runnerIdentity = {
|
|
6546
6909
|
service_name: registryReg.serviceName,
|
|
6547
6910
|
server_name: import_node_os3.default.hostname(),
|
|
@@ -6555,22 +6918,23 @@ async function runTasksLoop(context, options) {
|
|
|
6555
6918
|
}
|
|
6556
6919
|
try {
|
|
6557
6920
|
while (!context.isStop() && !stopRequested && context.tasksRunnerStop !== true) {
|
|
6558
|
-
|
|
6559
|
-
|
|
6921
|
+
const { maxParallel, pollMs, claimJitterMs, scanLimit } = readLoopRuntime(context);
|
|
6922
|
+
if (!runningControlPromise) {
|
|
6923
|
+
const claimedControlTask = await claimNextRunnableTask(
|
|
6560
6924
|
context,
|
|
6561
6925
|
tasksTable,
|
|
6562
6926
|
target,
|
|
6563
6927
|
registry,
|
|
6564
6928
|
10,
|
|
6565
|
-
|
|
6929
|
+
controlLaneTaskNames(),
|
|
6566
6930
|
runnerIdentity
|
|
6567
6931
|
);
|
|
6568
|
-
if (
|
|
6569
|
-
|
|
6932
|
+
if (claimedControlTask) {
|
|
6933
|
+
runningControlPromise = executeClaimedTask(
|
|
6570
6934
|
context,
|
|
6571
6935
|
tasksTable,
|
|
6572
6936
|
historyTable,
|
|
6573
|
-
|
|
6937
|
+
claimedControlTask,
|
|
6574
6938
|
registry,
|
|
6575
6939
|
runningTaskInstances
|
|
6576
6940
|
).then(async (outcome) => {
|
|
@@ -6581,7 +6945,7 @@ async function runTasksLoop(context, options) {
|
|
|
6581
6945
|
await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
|
|
6582
6946
|
}
|
|
6583
6947
|
}).finally(() => {
|
|
6584
|
-
|
|
6948
|
+
runningControlPromise = null;
|
|
6585
6949
|
});
|
|
6586
6950
|
}
|
|
6587
6951
|
}
|
|
@@ -6612,8 +6976,8 @@ async function runTasksLoop(context, options) {
|
|
|
6612
6976
|
runningPromises.add(p);
|
|
6613
6977
|
}
|
|
6614
6978
|
const wakePromises = [...runningPromises];
|
|
6615
|
-
if (
|
|
6616
|
-
wakePromises.push(
|
|
6979
|
+
if (runningControlPromise) {
|
|
6980
|
+
wakePromises.push(runningControlPromise);
|
|
6617
6981
|
}
|
|
6618
6982
|
if (wakePromises.length === 0) {
|
|
6619
6983
|
await sleepMs(pollMs);
|