@nmakarov/cli-toolkit 0.71.0 → 0.73.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 +233 -3
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +233 -3
- package/dist/cli-runner.js.map +1 -1
- package/dist/filedatabase.cjs.map +1 -1
- package/dist/filedatabase.js.map +1 -1
- package/dist/index.cjs +243 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +239 -3
- package/dist/index.js.map +1 -1
- package/dist/tasks.cjs +243 -3
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.js +239 -3
- package/dist/tasks.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1348,7 +1348,9 @@ __export(src_exports, {
|
|
|
1348
1348
|
ScrollableText: () => ScrollableText,
|
|
1349
1349
|
TaskGetLogs: () => TaskGetLogs,
|
|
1350
1350
|
TaskPauseRunner: () => TaskPauseRunner,
|
|
1351
|
+
TaskPauseTask: () => TaskPauseTask,
|
|
1351
1352
|
TaskPing: () => TaskPing,
|
|
1353
|
+
TaskResumeTask: () => TaskResumeTask,
|
|
1352
1354
|
TaskSampleProcess: () => TaskSampleProcess,
|
|
1353
1355
|
TaskSetRuntimeParam: () => TaskSetRuntimeParam,
|
|
1354
1356
|
TaskShellCommand: () => TaskShellCommand,
|
|
@@ -1363,6 +1365,8 @@ __export(src_exports, {
|
|
|
1363
1365
|
activateRelease: () => activateRelease,
|
|
1364
1366
|
appendDeployLog: () => appendDeployLog,
|
|
1365
1367
|
appendTaskIpcLog: () => appendTaskIpcLog,
|
|
1368
|
+
applyPauseTask: () => applyPauseTask,
|
|
1369
|
+
applyResumeTask: () => applyResumeTask,
|
|
1366
1370
|
applyRunnerPaused: () => applyRunnerPaused,
|
|
1367
1371
|
applyRuntimeParam: () => applyRuntimeParam,
|
|
1368
1372
|
applyRuntimePatch: () => applyRuntimePatch,
|
|
@@ -7411,6 +7415,9 @@ var DEFAULT_GROUP_MAX_INSTANCES = {
|
|
|
7411
7415
|
harvest: 1,
|
|
7412
7416
|
harvester: 0,
|
|
7413
7417
|
loader: 0,
|
|
7418
|
+
toolkit: 0,
|
|
7419
|
+
photocare: 0,
|
|
7420
|
+
/** @deprecated use photocare */
|
|
7414
7421
|
photos: 0,
|
|
7415
7422
|
photosprocessor: 0,
|
|
7416
7423
|
ingest: 0
|
|
@@ -7861,6 +7868,8 @@ var AbstractTask = class _AbstractTask {
|
|
|
7861
7868
|
constructor(context, task) {
|
|
7862
7869
|
this.context = context;
|
|
7863
7870
|
this.task = task;
|
|
7871
|
+
this._stopRequested = false;
|
|
7872
|
+
this._pauseRequested = false;
|
|
7864
7873
|
}
|
|
7865
7874
|
/**
|
|
7866
7875
|
* Return a short reason string when the task should be deferred (e.g. "locked
|
|
@@ -7878,6 +7887,26 @@ var AbstractTask = class _AbstractTask {
|
|
|
7878
7887
|
* @param {number} [_allowanceMs] Grace period the runner promises before hard exit.
|
|
7879
7888
|
*/
|
|
7880
7889
|
requestStop(_allowanceMs) {
|
|
7890
|
+
this._stopRequested = true;
|
|
7891
|
+
}
|
|
7892
|
+
/**
|
|
7893
|
+
* Cooperative pause signal (from `pauseTask` control-lane task). Long-running
|
|
7894
|
+
* tasks should finish the current unit of work, persist a checkpoint, and
|
|
7895
|
+
* return `{ success: true, results: { taskPaused: true, … } }` so the runner
|
|
7896
|
+
* keeps the row as `status=paused` instead of deleting it.
|
|
7897
|
+
*
|
|
7898
|
+
* @param {number} [_allowanceMs]
|
|
7899
|
+
*/
|
|
7900
|
+
requestPause(_allowanceMs) {
|
|
7901
|
+
this._pauseRequested = true;
|
|
7902
|
+
}
|
|
7903
|
+
/** @returns {boolean} */
|
|
7904
|
+
isStopRequested() {
|
|
7905
|
+
return this._stopRequested === true;
|
|
7906
|
+
}
|
|
7907
|
+
/** @returns {boolean} */
|
|
7908
|
+
isPauseRequested() {
|
|
7909
|
+
return this._pauseRequested === true;
|
|
7881
7910
|
}
|
|
7882
7911
|
/**
|
|
7883
7912
|
* Perform the task. Must be implemented by subclasses.
|
|
@@ -8584,6 +8613,8 @@ var CONTROL_LANE_TASK_NAMES = [
|
|
|
8584
8613
|
"pause",
|
|
8585
8614
|
"unpauseRunner",
|
|
8586
8615
|
"unpause",
|
|
8616
|
+
"pauseTask",
|
|
8617
|
+
"resumeTask",
|
|
8587
8618
|
"setRuntimeParam",
|
|
8588
8619
|
"setRunnerParam"
|
|
8589
8620
|
];
|
|
@@ -8788,6 +8819,190 @@ var TaskUnpauseRunner = class extends AbstractTask {
|
|
|
8788
8819
|
}
|
|
8789
8820
|
};
|
|
8790
8821
|
|
|
8822
|
+
// src/tasks/coreTasks/TaskPauseTask.js
|
|
8823
|
+
function parseProgressObject(progress) {
|
|
8824
|
+
if (progress == null || progress === "") return {};
|
|
8825
|
+
if (typeof progress === "object" && !Array.isArray(progress)) {
|
|
8826
|
+
return { ...progress };
|
|
8827
|
+
}
|
|
8828
|
+
if (typeof progress === "string") {
|
|
8829
|
+
const t = progress.trim();
|
|
8830
|
+
if (t.startsWith("{") || t.startsWith("[")) {
|
|
8831
|
+
try {
|
|
8832
|
+
const parsed = JSON.parse(t);
|
|
8833
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return { ...parsed };
|
|
8834
|
+
} catch {
|
|
8835
|
+
}
|
|
8836
|
+
}
|
|
8837
|
+
return { message: progress };
|
|
8838
|
+
}
|
|
8839
|
+
return { message: String(progress) };
|
|
8840
|
+
}
|
|
8841
|
+
async function applyPauseTask(context, taskId) {
|
|
8842
|
+
const db = context.db;
|
|
8843
|
+
if (!db) throw new Error("pauseTask: context.db is required");
|
|
8844
|
+
const id = String(taskId ?? "").trim();
|
|
8845
|
+
if (!id) throw new ParamError('pauseTask: param "taskId" is required');
|
|
8846
|
+
const { tasksTable } = queueToTableNames(context.tasksQueueName ?? "tasks");
|
|
8847
|
+
const row = await db(tasksTable).where({ id }).first();
|
|
8848
|
+
if (!row) {
|
|
8849
|
+
return { success: false, results: { error: `Task ${id} not found`, taskId: id } };
|
|
8850
|
+
}
|
|
8851
|
+
if (row.status === "paused") {
|
|
8852
|
+
return {
|
|
8853
|
+
success: true,
|
|
8854
|
+
results: { taskId: id, status: "paused", message: "Task already paused" }
|
|
8855
|
+
};
|
|
8856
|
+
}
|
|
8857
|
+
if (row.status === "idle") {
|
|
8858
|
+
const progress = parseProgressObject(row.progress);
|
|
8859
|
+
progress.pauseRequested = true;
|
|
8860
|
+
progress.pausedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8861
|
+
await db(tasksTable).where({ id }).update({
|
|
8862
|
+
status: "paused",
|
|
8863
|
+
status_changed_at: db.fn.now(),
|
|
8864
|
+
progress: toJsonColumn(progress)
|
|
8865
|
+
});
|
|
8866
|
+
context.logger?.warn?.(`[pauseTask] idle task ${id} (${row.name}) \u2192 paused`);
|
|
8867
|
+
return {
|
|
8868
|
+
success: true,
|
|
8869
|
+
results: { taskId: id, status: "paused", message: "Idle task paused" }
|
|
8870
|
+
};
|
|
8871
|
+
}
|
|
8872
|
+
if (row.status === "running") {
|
|
8873
|
+
const progress = parseProgressObject(row.progress);
|
|
8874
|
+
progress.pauseRequested = true;
|
|
8875
|
+
progress.pauseRequestedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8876
|
+
await db(tasksTable).where({ id }).update({
|
|
8877
|
+
progress: toJsonColumn(progress)
|
|
8878
|
+
});
|
|
8879
|
+
const inst = context.runningTaskInstances?.get?.(id);
|
|
8880
|
+
if (inst && typeof inst.requestPause === "function") {
|
|
8881
|
+
await inst.requestPause();
|
|
8882
|
+
context.logger?.warn?.(
|
|
8883
|
+
`[pauseTask] signaled running task ${id} (${row.name}) to pause after current unit`
|
|
8884
|
+
);
|
|
8885
|
+
return {
|
|
8886
|
+
success: true,
|
|
8887
|
+
results: {
|
|
8888
|
+
taskId: id,
|
|
8889
|
+
status: "running",
|
|
8890
|
+
signaled: true,
|
|
8891
|
+
message: "Pause requested; task will finish current unit then park as paused"
|
|
8892
|
+
}
|
|
8893
|
+
};
|
|
8894
|
+
}
|
|
8895
|
+
context.logger?.warn?.(
|
|
8896
|
+
`[pauseTask] stamped pauseRequested on ${id} (${row.name}) \u2014 not running in this process`
|
|
8897
|
+
);
|
|
8898
|
+
return {
|
|
8899
|
+
success: true,
|
|
8900
|
+
results: {
|
|
8901
|
+
taskId: id,
|
|
8902
|
+
status: "running",
|
|
8903
|
+
signaled: false,
|
|
8904
|
+
message: "pauseRequested stamped on task row; target runner must observe it (enqueue pauseTask on that service)"
|
|
8905
|
+
}
|
|
8906
|
+
};
|
|
8907
|
+
}
|
|
8908
|
+
return {
|
|
8909
|
+
success: false,
|
|
8910
|
+
results: {
|
|
8911
|
+
error: `Cannot pause task in status "${row.status}"`,
|
|
8912
|
+
taskId: id,
|
|
8913
|
+
status: row.status
|
|
8914
|
+
}
|
|
8915
|
+
};
|
|
8916
|
+
}
|
|
8917
|
+
async function applyResumeTask(context, taskId) {
|
|
8918
|
+
const db = context.db;
|
|
8919
|
+
if (!db) throw new Error("resumeTask: context.db is required");
|
|
8920
|
+
const id = String(taskId ?? "").trim();
|
|
8921
|
+
if (!id) throw new ParamError('resumeTask: param "taskId" is required');
|
|
8922
|
+
const { tasksTable } = queueToTableNames(context.tasksQueueName ?? "tasks");
|
|
8923
|
+
const row = await db(tasksTable).where({ id }).first();
|
|
8924
|
+
if (!row) {
|
|
8925
|
+
return { success: false, results: { error: `Task ${id} not found`, taskId: id } };
|
|
8926
|
+
}
|
|
8927
|
+
if (row.status === "idle") {
|
|
8928
|
+
return {
|
|
8929
|
+
success: true,
|
|
8930
|
+
results: { taskId: id, status: "idle", message: "Task already idle (runnable)" }
|
|
8931
|
+
};
|
|
8932
|
+
}
|
|
8933
|
+
if (row.status !== "paused") {
|
|
8934
|
+
return {
|
|
8935
|
+
success: false,
|
|
8936
|
+
results: {
|
|
8937
|
+
error: `Cannot resume task in status "${row.status}" (expected paused)`,
|
|
8938
|
+
taskId: id,
|
|
8939
|
+
status: row.status
|
|
8940
|
+
}
|
|
8941
|
+
};
|
|
8942
|
+
}
|
|
8943
|
+
const progress = parseProgressObject(row.progress);
|
|
8944
|
+
delete progress.pauseRequested;
|
|
8945
|
+
delete progress.pauseRequestedAt;
|
|
8946
|
+
delete progress.pausedAt;
|
|
8947
|
+
progress.resumedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8948
|
+
await db(tasksTable).where({ id }).update({
|
|
8949
|
+
status: "idle",
|
|
8950
|
+
status_changed_at: db.fn.now(),
|
|
8951
|
+
started_at: null,
|
|
8952
|
+
completed_at: null,
|
|
8953
|
+
success: null,
|
|
8954
|
+
progress: toJsonColumn(progress),
|
|
8955
|
+
// Clear claim binding so any matching worker can pick it up.
|
|
8956
|
+
service_name: null,
|
|
8957
|
+
server_name: null,
|
|
8958
|
+
instance_number: null,
|
|
8959
|
+
next_run_at: null
|
|
8960
|
+
});
|
|
8961
|
+
context.logger?.warn?.(`[resumeTask] paused task ${id} (${row.name}) \u2192 idle`);
|
|
8962
|
+
return {
|
|
8963
|
+
success: true,
|
|
8964
|
+
results: { taskId: id, status: "idle", message: "Task resumed (idle; will be claimed)" }
|
|
8965
|
+
};
|
|
8966
|
+
}
|
|
8967
|
+
var TaskPauseTask = class extends AbstractTask {
|
|
8968
|
+
static taskName = "pauseTask";
|
|
8969
|
+
static description = "Pause a specific task: finish current unit, persist status=paused";
|
|
8970
|
+
static defaultWaitForResult = true;
|
|
8971
|
+
static async resolveCustomParams(context, overrides = {}) {
|
|
8972
|
+
const merged = AbstractTask._mergeTypedParams(
|
|
8973
|
+
context,
|
|
8974
|
+
"task-pause-task",
|
|
8975
|
+
{ taskId: "string" },
|
|
8976
|
+
overrides
|
|
8977
|
+
);
|
|
8978
|
+
const taskId = typeof merged.taskId === "string" ? merged.taskId.trim() : "";
|
|
8979
|
+
if (!taskId) throw new ParamError('pauseTask: param "taskId" is required');
|
|
8980
|
+
return { taskId };
|
|
8981
|
+
}
|
|
8982
|
+
async run() {
|
|
8983
|
+
return applyPauseTask(this.context, this.task?.params?.taskId);
|
|
8984
|
+
}
|
|
8985
|
+
};
|
|
8986
|
+
var TaskResumeTask = class extends AbstractTask {
|
|
8987
|
+
static taskName = "resumeTask";
|
|
8988
|
+
static description = "Resume a paused task (status paused \u2192 idle)";
|
|
8989
|
+
static defaultWaitForResult = true;
|
|
8990
|
+
static async resolveCustomParams(context, overrides = {}) {
|
|
8991
|
+
const merged = AbstractTask._mergeTypedParams(
|
|
8992
|
+
context,
|
|
8993
|
+
"task-resume-task",
|
|
8994
|
+
{ taskId: "string" },
|
|
8995
|
+
overrides
|
|
8996
|
+
);
|
|
8997
|
+
const taskId = typeof merged.taskId === "string" ? merged.taskId.trim() : "";
|
|
8998
|
+
if (!taskId) throw new ParamError('resumeTask: param "taskId" is required');
|
|
8999
|
+
return { taskId };
|
|
9000
|
+
}
|
|
9001
|
+
async run() {
|
|
9002
|
+
return applyResumeTask(this.context, this.task?.params?.taskId);
|
|
9003
|
+
}
|
|
9004
|
+
};
|
|
9005
|
+
|
|
8791
9006
|
// src/tasks/coreTasks/TaskGetLogs.js
|
|
8792
9007
|
var TaskGetLogs = class extends AbstractTask {
|
|
8793
9008
|
/**
|
|
@@ -9006,7 +9221,7 @@ var TasksRegistry = class _TasksRegistry {
|
|
|
9006
9221
|
* @returns {TasksRegistry}
|
|
9007
9222
|
*/
|
|
9008
9223
|
static withCoreTasks() {
|
|
9009
|
-
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("pauseRunner", TaskPauseRunner).add("pause", TaskPauseRunner).add("unpauseRunner", TaskUnpauseRunner).add("unpause", TaskUnpauseRunner).add("getLogs", TaskGetLogs).add("setRuntimeParam", TaskSetRuntimeParam).add("setRunnerParam", TaskSetRuntimeParam);
|
|
9224
|
+
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("pauseRunner", TaskPauseRunner).add("pause", TaskPauseRunner).add("unpauseRunner", TaskUnpauseRunner).add("unpause", TaskUnpauseRunner).add("pauseTask", TaskPauseTask).add("resumeTask", TaskResumeTask).add("getLogs", TaskGetLogs).add("setRuntimeParam", TaskSetRuntimeParam).add("setRunnerParam", TaskSetRuntimeParam);
|
|
9010
9225
|
}
|
|
9011
9226
|
/**
|
|
9012
9227
|
* Register a single task class under a name. Overwrites any previous entry.
|
|
@@ -9113,6 +9328,8 @@ var SERVICE_TASK_NAMES = [
|
|
|
9113
9328
|
"pauseRunner",
|
|
9114
9329
|
"unpause",
|
|
9115
9330
|
"unpauseRunner",
|
|
9331
|
+
"pauseTask",
|
|
9332
|
+
"resumeTask",
|
|
9116
9333
|
"shellCommand",
|
|
9117
9334
|
"systemInfo",
|
|
9118
9335
|
"info",
|
|
@@ -9408,11 +9625,12 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
|
|
|
9408
9625
|
} finally {
|
|
9409
9626
|
runningTaskInstances.delete(row.id);
|
|
9410
9627
|
}
|
|
9628
|
+
const taskPaused = success && results && typeof results === "object" && results.taskPaused === true;
|
|
9411
9629
|
await db(historyTable).insert(
|
|
9412
9630
|
taskHistoryInsertFromQueueRow(row, {
|
|
9413
9631
|
completed_at: /* @__PURE__ */ new Date(),
|
|
9414
9632
|
success,
|
|
9415
|
-
status: success ? "completed" : "failed",
|
|
9633
|
+
status: taskPaused ? "paused" : success ? "completed" : "failed",
|
|
9416
9634
|
status_changed_at: db.fn.now(),
|
|
9417
9635
|
params: toJsonColumn(row.params),
|
|
9418
9636
|
results: toJsonColumn(results)
|
|
@@ -9435,7 +9653,24 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
|
|
|
9435
9653
|
details: results
|
|
9436
9654
|
});
|
|
9437
9655
|
}
|
|
9438
|
-
if (
|
|
9656
|
+
if (taskPaused) {
|
|
9657
|
+
const checkpointParams = results.checkpointParams && typeof results.checkpointParams === "object" ? results.checkpointParams : row.params;
|
|
9658
|
+
const progressPayload = results.progress != null ? results.progress : { paused: true, pausedAt: (/* @__PURE__ */ new Date()).toISOString(), message: "paused" };
|
|
9659
|
+
await db(tasksTable).where({ id: row.id }).update({
|
|
9660
|
+
started_at: null,
|
|
9661
|
+
completed_at: /* @__PURE__ */ new Date(),
|
|
9662
|
+
success: true,
|
|
9663
|
+
results: toJsonColumn(results),
|
|
9664
|
+
params: toJsonColumn(checkpointParams),
|
|
9665
|
+
progress: toJsonColumn(progressPayload),
|
|
9666
|
+
status: "paused",
|
|
9667
|
+
status_changed_at: db.fn.now(),
|
|
9668
|
+
past_due: null,
|
|
9669
|
+
service_name: null,
|
|
9670
|
+
server_name: null,
|
|
9671
|
+
instance_number: null
|
|
9672
|
+
});
|
|
9673
|
+
} else if (row.schedule) {
|
|
9439
9674
|
if (success) {
|
|
9440
9675
|
let nextRunAt = null;
|
|
9441
9676
|
try {
|
|
@@ -9563,6 +9798,7 @@ async function runTasksLoop(context, options) {
|
|
|
9563
9798
|
}
|
|
9564
9799
|
const runningPromises = /* @__PURE__ */ new Set();
|
|
9565
9800
|
const runningTaskInstances = /* @__PURE__ */ new Map();
|
|
9801
|
+
context.runningTaskInstances = runningTaskInstances;
|
|
9566
9802
|
let runningControlPromise = null;
|
|
9567
9803
|
let stopRequested = false;
|
|
9568
9804
|
let stopAllowanceMs = Number(context.stopAllowanceMs) > 0 ? Number(context.stopAllowanceMs) : 6e4;
|
|
@@ -9951,7 +10187,9 @@ var TasksManager = class _TasksManager {
|
|
|
9951
10187
|
ScrollableText,
|
|
9952
10188
|
TaskGetLogs,
|
|
9953
10189
|
TaskPauseRunner,
|
|
10190
|
+
TaskPauseTask,
|
|
9954
10191
|
TaskPing,
|
|
10192
|
+
TaskResumeTask,
|
|
9955
10193
|
TaskSampleProcess,
|
|
9956
10194
|
TaskSetRuntimeParam,
|
|
9957
10195
|
TaskShellCommand,
|
|
@@ -9966,6 +10204,8 @@ var TasksManager = class _TasksManager {
|
|
|
9966
10204
|
activateRelease,
|
|
9967
10205
|
appendDeployLog,
|
|
9968
10206
|
appendTaskIpcLog,
|
|
10207
|
+
applyPauseTask,
|
|
10208
|
+
applyResumeTask,
|
|
9969
10209
|
applyRunnerPaused,
|
|
9970
10210
|
applyRuntimeParam,
|
|
9971
10211
|
applyRuntimePatch,
|