@nmakarov/cli-toolkit 0.49.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 +377 -16
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +377 -16
- package/dist/cli-runner.js.map +1 -1
- package/dist/index.cjs +318 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +309 -17
- package/dist/index.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
|
@@ -3969,6 +3969,51 @@ async function dropLegacyTaskNameColumn(db, tableNames, { dryRun, log, label })
|
|
|
3969
3969
|
}
|
|
3970
3970
|
return actions;
|
|
3971
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
|
+
}
|
|
3972
4017
|
async function updateTaskProgress(context, tasksTable, taskId, progress) {
|
|
3973
4018
|
const db = getDb(context);
|
|
3974
4019
|
await db(tasksTable).where({ id: taskId }).update({
|
|
@@ -3984,6 +4029,19 @@ function getDb2(context) {
|
|
|
3984
4029
|
}
|
|
3985
4030
|
return db;
|
|
3986
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
|
+
}
|
|
3987
4045
|
var DEFAULT_GROUP_MAX_INSTANCES = {
|
|
3988
4046
|
intake: 1,
|
|
3989
4047
|
harvest: 1,
|
|
@@ -4182,11 +4240,33 @@ async function touchServicesRegistry(context, registration) {
|
|
|
4182
4240
|
pid
|
|
4183
4241
|
});
|
|
4184
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
|
+
}
|
|
4185
4254
|
async function unregisterServicesRegistry(context, registration) {
|
|
4186
4255
|
const db = getDb2(context);
|
|
4187
4256
|
await db(registration.registryTable).where({ id: registration.rowId }).delete();
|
|
4188
4257
|
context.logger.info?.(`[services-registry] unregistered name=${registration.serviceName} id=${registration.rowId}`);
|
|
4189
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
|
+
}
|
|
4190
4270
|
|
|
4191
4271
|
// src/tasks/taskLogs.js
|
|
4192
4272
|
import path4 from "path";
|
|
@@ -6145,6 +6225,273 @@ var TaskGetLogs = class extends AbstractTask {
|
|
|
6145
6225
|
}
|
|
6146
6226
|
};
|
|
6147
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
|
+
|
|
6148
6495
|
// src/tasks/TasksRegistry.js
|
|
6149
6496
|
var TasksRegistry = class _TasksRegistry {
|
|
6150
6497
|
/**
|
|
@@ -6163,7 +6510,7 @@ var TasksRegistry = class _TasksRegistry {
|
|
|
6163
6510
|
* @returns {TasksRegistry}
|
|
6164
6511
|
*/
|
|
6165
6512
|
static withCoreTasks() {
|
|
6166
|
-
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);
|
|
6167
6514
|
}
|
|
6168
6515
|
/**
|
|
6169
6516
|
* Register a single task class under a name. Overwrites any previous entry.
|
|
@@ -6492,18 +6839,23 @@ async function claimNextRunnableTask(context, tasksTable, serviceGroup, registry
|
|
|
6492
6839
|
async function runTasksLoop(context, options) {
|
|
6493
6840
|
const queueName = options.queueName ?? "tasks";
|
|
6494
6841
|
const target = options.target;
|
|
6495
|
-
const pollMs = options.pollMs ?? 1e3;
|
|
6496
|
-
const claimJitterMs = options.claimJitterMs ?? 0;
|
|
6497
|
-
const maxParallel = options.maxParallel ?? 32;
|
|
6498
|
-
const scanLimit = options.scanLimit ?? 100;
|
|
6499
6842
|
const allowedTasks = normalizeAllowedTasks(options.allowedTasks);
|
|
6500
6843
|
const registry = normalizeRegistry(options.registry);
|
|
6501
6844
|
const { tasksTable, historyTable } = queueToTableNames(queueName);
|
|
6502
6845
|
if (!target) throw new Error("runTasksLoop: target is required");
|
|
6503
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
|
+
}
|
|
6504
6856
|
const runningPromises = /* @__PURE__ */ new Set();
|
|
6505
6857
|
const runningTaskInstances = /* @__PURE__ */ new Map();
|
|
6506
|
-
let
|
|
6858
|
+
let runningControlPromise = null;
|
|
6507
6859
|
let stopRequested = false;
|
|
6508
6860
|
let stopAllowanceMs = 5e3;
|
|
6509
6861
|
context.tasksRunnerStop = false;
|
|
@@ -6514,9 +6866,16 @@ async function runTasksLoop(context, options) {
|
|
|
6514
6866
|
if (hbGroup) {
|
|
6515
6867
|
const hbIntervalMs = options.runnerHeartbeatIntervalMs ?? 1e4;
|
|
6516
6868
|
const staleMs = options.runnerHeartbeatStaleMs ?? 45e3;
|
|
6869
|
+
const loop0 = readLoopRuntime(context);
|
|
6517
6870
|
const defaultMeta = {
|
|
6518
6871
|
component: "tasks-runner",
|
|
6519
|
-
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
|
+
}
|
|
6520
6879
|
};
|
|
6521
6880
|
registryReg = await registerInServicesRegistry(context, {
|
|
6522
6881
|
queueName,
|
|
@@ -6529,6 +6888,7 @@ async function runTasksLoop(context, options) {
|
|
|
6529
6888
|
enforceMaxInstances: options.runnerEnforceMaxInstances ?? true,
|
|
6530
6889
|
metadata: options.runnerMetadata ?? defaultMeta
|
|
6531
6890
|
});
|
|
6891
|
+
context.servicesRegistry = registryReg;
|
|
6532
6892
|
runnerIdentity = {
|
|
6533
6893
|
service_name: registryReg.serviceName,
|
|
6534
6894
|
server_name: os3.hostname(),
|
|
@@ -6542,22 +6902,23 @@ async function runTasksLoop(context, options) {
|
|
|
6542
6902
|
}
|
|
6543
6903
|
try {
|
|
6544
6904
|
while (!context.isStop() && !stopRequested && context.tasksRunnerStop !== true) {
|
|
6545
|
-
|
|
6546
|
-
|
|
6905
|
+
const { maxParallel, pollMs, claimJitterMs, scanLimit } = readLoopRuntime(context);
|
|
6906
|
+
if (!runningControlPromise) {
|
|
6907
|
+
const claimedControlTask = await claimNextRunnableTask(
|
|
6547
6908
|
context,
|
|
6548
6909
|
tasksTable,
|
|
6549
6910
|
target,
|
|
6550
6911
|
registry,
|
|
6551
6912
|
10,
|
|
6552
|
-
|
|
6913
|
+
controlLaneTaskNames(),
|
|
6553
6914
|
runnerIdentity
|
|
6554
6915
|
);
|
|
6555
|
-
if (
|
|
6556
|
-
|
|
6916
|
+
if (claimedControlTask) {
|
|
6917
|
+
runningControlPromise = executeClaimedTask(
|
|
6557
6918
|
context,
|
|
6558
6919
|
tasksTable,
|
|
6559
6920
|
historyTable,
|
|
6560
|
-
|
|
6921
|
+
claimedControlTask,
|
|
6561
6922
|
registry,
|
|
6562
6923
|
runningTaskInstances
|
|
6563
6924
|
).then(async (outcome) => {
|
|
@@ -6568,7 +6929,7 @@ async function runTasksLoop(context, options) {
|
|
|
6568
6929
|
await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
|
|
6569
6930
|
}
|
|
6570
6931
|
}).finally(() => {
|
|
6571
|
-
|
|
6932
|
+
runningControlPromise = null;
|
|
6572
6933
|
});
|
|
6573
6934
|
}
|
|
6574
6935
|
}
|
|
@@ -6599,8 +6960,8 @@ async function runTasksLoop(context, options) {
|
|
|
6599
6960
|
runningPromises.add(p);
|
|
6600
6961
|
}
|
|
6601
6962
|
const wakePromises = [...runningPromises];
|
|
6602
|
-
if (
|
|
6603
|
-
wakePromises.push(
|
|
6963
|
+
if (runningControlPromise) {
|
|
6964
|
+
wakePromises.push(runningControlPromise);
|
|
6604
6965
|
}
|
|
6605
6966
|
if (wakePromises.length === 0) {
|
|
6606
6967
|
await sleepMs(pollMs);
|