@nmakarov/cli-toolkit 0.72.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 +230 -3
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +230 -3
- package/dist/cli-runner.js.map +1 -1
- package/dist/index.cjs +240 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +236 -3
- package/dist/index.js.map +1 -1
- package/dist/tasks.cjs +240 -3
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.js +236 -3
- package/dist/tasks.js.map +1 -1
- package/package.json +1 -1
package/dist/tasks.cjs
CHANGED
|
@@ -36,7 +36,9 @@ __export(tasks_exports, {
|
|
|
36
36
|
SERVICE_TASK_NAMES: () => SERVICE_TASK_NAMES,
|
|
37
37
|
TaskGetLogs: () => TaskGetLogs,
|
|
38
38
|
TaskPauseRunner: () => TaskPauseRunner,
|
|
39
|
+
TaskPauseTask: () => TaskPauseTask,
|
|
39
40
|
TaskPing: () => TaskPing,
|
|
41
|
+
TaskResumeTask: () => TaskResumeTask,
|
|
40
42
|
TaskSampleProcess: () => TaskSampleProcess,
|
|
41
43
|
TaskSetRuntimeParam: () => TaskSetRuntimeParam,
|
|
42
44
|
TaskShellCommand: () => TaskShellCommand,
|
|
@@ -47,6 +49,8 @@ __export(tasks_exports, {
|
|
|
47
49
|
TasksManager: () => TasksManager,
|
|
48
50
|
TasksRegistry: () => TasksRegistry,
|
|
49
51
|
appendTaskIpcLog: () => appendTaskIpcLog,
|
|
52
|
+
applyPauseTask: () => applyPauseTask,
|
|
53
|
+
applyResumeTask: () => applyResumeTask,
|
|
50
54
|
applyRunnerPaused: () => applyRunnerPaused,
|
|
51
55
|
applyRuntimeParam: () => applyRuntimeParam,
|
|
52
56
|
applyRuntimePatch: () => applyRuntimePatch,
|
|
@@ -2141,6 +2145,8 @@ var AbstractTask = class _AbstractTask {
|
|
|
2141
2145
|
constructor(context, task) {
|
|
2142
2146
|
this.context = context;
|
|
2143
2147
|
this.task = task;
|
|
2148
|
+
this._stopRequested = false;
|
|
2149
|
+
this._pauseRequested = false;
|
|
2144
2150
|
}
|
|
2145
2151
|
/**
|
|
2146
2152
|
* Return a short reason string when the task should be deferred (e.g. "locked
|
|
@@ -2158,6 +2164,26 @@ var AbstractTask = class _AbstractTask {
|
|
|
2158
2164
|
* @param {number} [_allowanceMs] Grace period the runner promises before hard exit.
|
|
2159
2165
|
*/
|
|
2160
2166
|
requestStop(_allowanceMs) {
|
|
2167
|
+
this._stopRequested = true;
|
|
2168
|
+
}
|
|
2169
|
+
/**
|
|
2170
|
+
* Cooperative pause signal (from `pauseTask` control-lane task). Long-running
|
|
2171
|
+
* tasks should finish the current unit of work, persist a checkpoint, and
|
|
2172
|
+
* return `{ success: true, results: { taskPaused: true, … } }` so the runner
|
|
2173
|
+
* keeps the row as `status=paused` instead of deleting it.
|
|
2174
|
+
*
|
|
2175
|
+
* @param {number} [_allowanceMs]
|
|
2176
|
+
*/
|
|
2177
|
+
requestPause(_allowanceMs) {
|
|
2178
|
+
this._pauseRequested = true;
|
|
2179
|
+
}
|
|
2180
|
+
/** @returns {boolean} */
|
|
2181
|
+
isStopRequested() {
|
|
2182
|
+
return this._stopRequested === true;
|
|
2183
|
+
}
|
|
2184
|
+
/** @returns {boolean} */
|
|
2185
|
+
isPauseRequested() {
|
|
2186
|
+
return this._pauseRequested === true;
|
|
2161
2187
|
}
|
|
2162
2188
|
/**
|
|
2163
2189
|
* Perform the task. Must be implemented by subclasses.
|
|
@@ -2864,6 +2890,8 @@ var CONTROL_LANE_TASK_NAMES = [
|
|
|
2864
2890
|
"pause",
|
|
2865
2891
|
"unpauseRunner",
|
|
2866
2892
|
"unpause",
|
|
2893
|
+
"pauseTask",
|
|
2894
|
+
"resumeTask",
|
|
2867
2895
|
"setRuntimeParam",
|
|
2868
2896
|
"setRunnerParam"
|
|
2869
2897
|
];
|
|
@@ -3068,6 +3096,190 @@ var TaskUnpauseRunner = class extends AbstractTask {
|
|
|
3068
3096
|
}
|
|
3069
3097
|
};
|
|
3070
3098
|
|
|
3099
|
+
// src/tasks/coreTasks/TaskPauseTask.js
|
|
3100
|
+
function parseProgressObject(progress) {
|
|
3101
|
+
if (progress == null || progress === "") return {};
|
|
3102
|
+
if (typeof progress === "object" && !Array.isArray(progress)) {
|
|
3103
|
+
return { ...progress };
|
|
3104
|
+
}
|
|
3105
|
+
if (typeof progress === "string") {
|
|
3106
|
+
const t = progress.trim();
|
|
3107
|
+
if (t.startsWith("{") || t.startsWith("[")) {
|
|
3108
|
+
try {
|
|
3109
|
+
const parsed = JSON.parse(t);
|
|
3110
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return { ...parsed };
|
|
3111
|
+
} catch {
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
return { message: progress };
|
|
3115
|
+
}
|
|
3116
|
+
return { message: String(progress) };
|
|
3117
|
+
}
|
|
3118
|
+
async function applyPauseTask(context, taskId) {
|
|
3119
|
+
const db = context.db;
|
|
3120
|
+
if (!db) throw new Error("pauseTask: context.db is required");
|
|
3121
|
+
const id = String(taskId ?? "").trim();
|
|
3122
|
+
if (!id) throw new ParamError('pauseTask: param "taskId" is required');
|
|
3123
|
+
const { tasksTable } = queueToTableNames(context.tasksQueueName ?? "tasks");
|
|
3124
|
+
const row = await db(tasksTable).where({ id }).first();
|
|
3125
|
+
if (!row) {
|
|
3126
|
+
return { success: false, results: { error: `Task ${id} not found`, taskId: id } };
|
|
3127
|
+
}
|
|
3128
|
+
if (row.status === "paused") {
|
|
3129
|
+
return {
|
|
3130
|
+
success: true,
|
|
3131
|
+
results: { taskId: id, status: "paused", message: "Task already paused" }
|
|
3132
|
+
};
|
|
3133
|
+
}
|
|
3134
|
+
if (row.status === "idle") {
|
|
3135
|
+
const progress = parseProgressObject(row.progress);
|
|
3136
|
+
progress.pauseRequested = true;
|
|
3137
|
+
progress.pausedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3138
|
+
await db(tasksTable).where({ id }).update({
|
|
3139
|
+
status: "paused",
|
|
3140
|
+
status_changed_at: db.fn.now(),
|
|
3141
|
+
progress: toJsonColumn(progress)
|
|
3142
|
+
});
|
|
3143
|
+
context.logger?.warn?.(`[pauseTask] idle task ${id} (${row.name}) \u2192 paused`);
|
|
3144
|
+
return {
|
|
3145
|
+
success: true,
|
|
3146
|
+
results: { taskId: id, status: "paused", message: "Idle task paused" }
|
|
3147
|
+
};
|
|
3148
|
+
}
|
|
3149
|
+
if (row.status === "running") {
|
|
3150
|
+
const progress = parseProgressObject(row.progress);
|
|
3151
|
+
progress.pauseRequested = true;
|
|
3152
|
+
progress.pauseRequestedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3153
|
+
await db(tasksTable).where({ id }).update({
|
|
3154
|
+
progress: toJsonColumn(progress)
|
|
3155
|
+
});
|
|
3156
|
+
const inst = context.runningTaskInstances?.get?.(id);
|
|
3157
|
+
if (inst && typeof inst.requestPause === "function") {
|
|
3158
|
+
await inst.requestPause();
|
|
3159
|
+
context.logger?.warn?.(
|
|
3160
|
+
`[pauseTask] signaled running task ${id} (${row.name}) to pause after current unit`
|
|
3161
|
+
);
|
|
3162
|
+
return {
|
|
3163
|
+
success: true,
|
|
3164
|
+
results: {
|
|
3165
|
+
taskId: id,
|
|
3166
|
+
status: "running",
|
|
3167
|
+
signaled: true,
|
|
3168
|
+
message: "Pause requested; task will finish current unit then park as paused"
|
|
3169
|
+
}
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3172
|
+
context.logger?.warn?.(
|
|
3173
|
+
`[pauseTask] stamped pauseRequested on ${id} (${row.name}) \u2014 not running in this process`
|
|
3174
|
+
);
|
|
3175
|
+
return {
|
|
3176
|
+
success: true,
|
|
3177
|
+
results: {
|
|
3178
|
+
taskId: id,
|
|
3179
|
+
status: "running",
|
|
3180
|
+
signaled: false,
|
|
3181
|
+
message: "pauseRequested stamped on task row; target runner must observe it (enqueue pauseTask on that service)"
|
|
3182
|
+
}
|
|
3183
|
+
};
|
|
3184
|
+
}
|
|
3185
|
+
return {
|
|
3186
|
+
success: false,
|
|
3187
|
+
results: {
|
|
3188
|
+
error: `Cannot pause task in status "${row.status}"`,
|
|
3189
|
+
taskId: id,
|
|
3190
|
+
status: row.status
|
|
3191
|
+
}
|
|
3192
|
+
};
|
|
3193
|
+
}
|
|
3194
|
+
async function applyResumeTask(context, taskId) {
|
|
3195
|
+
const db = context.db;
|
|
3196
|
+
if (!db) throw new Error("resumeTask: context.db is required");
|
|
3197
|
+
const id = String(taskId ?? "").trim();
|
|
3198
|
+
if (!id) throw new ParamError('resumeTask: param "taskId" is required');
|
|
3199
|
+
const { tasksTable } = queueToTableNames(context.tasksQueueName ?? "tasks");
|
|
3200
|
+
const row = await db(tasksTable).where({ id }).first();
|
|
3201
|
+
if (!row) {
|
|
3202
|
+
return { success: false, results: { error: `Task ${id} not found`, taskId: id } };
|
|
3203
|
+
}
|
|
3204
|
+
if (row.status === "idle") {
|
|
3205
|
+
return {
|
|
3206
|
+
success: true,
|
|
3207
|
+
results: { taskId: id, status: "idle", message: "Task already idle (runnable)" }
|
|
3208
|
+
};
|
|
3209
|
+
}
|
|
3210
|
+
if (row.status !== "paused") {
|
|
3211
|
+
return {
|
|
3212
|
+
success: false,
|
|
3213
|
+
results: {
|
|
3214
|
+
error: `Cannot resume task in status "${row.status}" (expected paused)`,
|
|
3215
|
+
taskId: id,
|
|
3216
|
+
status: row.status
|
|
3217
|
+
}
|
|
3218
|
+
};
|
|
3219
|
+
}
|
|
3220
|
+
const progress = parseProgressObject(row.progress);
|
|
3221
|
+
delete progress.pauseRequested;
|
|
3222
|
+
delete progress.pauseRequestedAt;
|
|
3223
|
+
delete progress.pausedAt;
|
|
3224
|
+
progress.resumedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3225
|
+
await db(tasksTable).where({ id }).update({
|
|
3226
|
+
status: "idle",
|
|
3227
|
+
status_changed_at: db.fn.now(),
|
|
3228
|
+
started_at: null,
|
|
3229
|
+
completed_at: null,
|
|
3230
|
+
success: null,
|
|
3231
|
+
progress: toJsonColumn(progress),
|
|
3232
|
+
// Clear claim binding so any matching worker can pick it up.
|
|
3233
|
+
service_name: null,
|
|
3234
|
+
server_name: null,
|
|
3235
|
+
instance_number: null,
|
|
3236
|
+
next_run_at: null
|
|
3237
|
+
});
|
|
3238
|
+
context.logger?.warn?.(`[resumeTask] paused task ${id} (${row.name}) \u2192 idle`);
|
|
3239
|
+
return {
|
|
3240
|
+
success: true,
|
|
3241
|
+
results: { taskId: id, status: "idle", message: "Task resumed (idle; will be claimed)" }
|
|
3242
|
+
};
|
|
3243
|
+
}
|
|
3244
|
+
var TaskPauseTask = class extends AbstractTask {
|
|
3245
|
+
static taskName = "pauseTask";
|
|
3246
|
+
static description = "Pause a specific task: finish current unit, persist status=paused";
|
|
3247
|
+
static defaultWaitForResult = true;
|
|
3248
|
+
static async resolveCustomParams(context, overrides = {}) {
|
|
3249
|
+
const merged = AbstractTask._mergeTypedParams(
|
|
3250
|
+
context,
|
|
3251
|
+
"task-pause-task",
|
|
3252
|
+
{ taskId: "string" },
|
|
3253
|
+
overrides
|
|
3254
|
+
);
|
|
3255
|
+
const taskId = typeof merged.taskId === "string" ? merged.taskId.trim() : "";
|
|
3256
|
+
if (!taskId) throw new ParamError('pauseTask: param "taskId" is required');
|
|
3257
|
+
return { taskId };
|
|
3258
|
+
}
|
|
3259
|
+
async run() {
|
|
3260
|
+
return applyPauseTask(this.context, this.task?.params?.taskId);
|
|
3261
|
+
}
|
|
3262
|
+
};
|
|
3263
|
+
var TaskResumeTask = class extends AbstractTask {
|
|
3264
|
+
static taskName = "resumeTask";
|
|
3265
|
+
static description = "Resume a paused task (status paused \u2192 idle)";
|
|
3266
|
+
static defaultWaitForResult = true;
|
|
3267
|
+
static async resolveCustomParams(context, overrides = {}) {
|
|
3268
|
+
const merged = AbstractTask._mergeTypedParams(
|
|
3269
|
+
context,
|
|
3270
|
+
"task-resume-task",
|
|
3271
|
+
{ taskId: "string" },
|
|
3272
|
+
overrides
|
|
3273
|
+
);
|
|
3274
|
+
const taskId = typeof merged.taskId === "string" ? merged.taskId.trim() : "";
|
|
3275
|
+
if (!taskId) throw new ParamError('resumeTask: param "taskId" is required');
|
|
3276
|
+
return { taskId };
|
|
3277
|
+
}
|
|
3278
|
+
async run() {
|
|
3279
|
+
return applyResumeTask(this.context, this.task?.params?.taskId);
|
|
3280
|
+
}
|
|
3281
|
+
};
|
|
3282
|
+
|
|
3071
3283
|
// src/tasks/coreTasks/TaskGetLogs.js
|
|
3072
3284
|
var TaskGetLogs = class extends AbstractTask {
|
|
3073
3285
|
/**
|
|
@@ -3286,7 +3498,7 @@ var TasksRegistry = class _TasksRegistry {
|
|
|
3286
3498
|
* @returns {TasksRegistry}
|
|
3287
3499
|
*/
|
|
3288
3500
|
static withCoreTasks() {
|
|
3289
|
-
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);
|
|
3501
|
+
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);
|
|
3290
3502
|
}
|
|
3291
3503
|
/**
|
|
3292
3504
|
* Register a single task class under a name. Overwrites any previous entry.
|
|
@@ -3393,6 +3605,8 @@ var SERVICE_TASK_NAMES = [
|
|
|
3393
3605
|
"pauseRunner",
|
|
3394
3606
|
"unpause",
|
|
3395
3607
|
"unpauseRunner",
|
|
3608
|
+
"pauseTask",
|
|
3609
|
+
"resumeTask",
|
|
3396
3610
|
"shellCommand",
|
|
3397
3611
|
"systemInfo",
|
|
3398
3612
|
"info",
|
|
@@ -3688,11 +3902,12 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
|
|
|
3688
3902
|
} finally {
|
|
3689
3903
|
runningTaskInstances.delete(row.id);
|
|
3690
3904
|
}
|
|
3905
|
+
const taskPaused = success && results && typeof results === "object" && results.taskPaused === true;
|
|
3691
3906
|
await db(historyTable).insert(
|
|
3692
3907
|
taskHistoryInsertFromQueueRow(row, {
|
|
3693
3908
|
completed_at: /* @__PURE__ */ new Date(),
|
|
3694
3909
|
success,
|
|
3695
|
-
status: success ? "completed" : "failed",
|
|
3910
|
+
status: taskPaused ? "paused" : success ? "completed" : "failed",
|
|
3696
3911
|
status_changed_at: db.fn.now(),
|
|
3697
3912
|
params: toJsonColumn(row.params),
|
|
3698
3913
|
results: toJsonColumn(results)
|
|
@@ -3715,7 +3930,24 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
|
|
|
3715
3930
|
details: results
|
|
3716
3931
|
});
|
|
3717
3932
|
}
|
|
3718
|
-
if (
|
|
3933
|
+
if (taskPaused) {
|
|
3934
|
+
const checkpointParams = results.checkpointParams && typeof results.checkpointParams === "object" ? results.checkpointParams : row.params;
|
|
3935
|
+
const progressPayload = results.progress != null ? results.progress : { paused: true, pausedAt: (/* @__PURE__ */ new Date()).toISOString(), message: "paused" };
|
|
3936
|
+
await db(tasksTable).where({ id: row.id }).update({
|
|
3937
|
+
started_at: null,
|
|
3938
|
+
completed_at: /* @__PURE__ */ new Date(),
|
|
3939
|
+
success: true,
|
|
3940
|
+
results: toJsonColumn(results),
|
|
3941
|
+
params: toJsonColumn(checkpointParams),
|
|
3942
|
+
progress: toJsonColumn(progressPayload),
|
|
3943
|
+
status: "paused",
|
|
3944
|
+
status_changed_at: db.fn.now(),
|
|
3945
|
+
past_due: null,
|
|
3946
|
+
service_name: null,
|
|
3947
|
+
server_name: null,
|
|
3948
|
+
instance_number: null
|
|
3949
|
+
});
|
|
3950
|
+
} else if (row.schedule) {
|
|
3719
3951
|
if (success) {
|
|
3720
3952
|
let nextRunAt = null;
|
|
3721
3953
|
try {
|
|
@@ -3843,6 +4075,7 @@ async function runTasksLoop(context, options) {
|
|
|
3843
4075
|
}
|
|
3844
4076
|
const runningPromises = /* @__PURE__ */ new Set();
|
|
3845
4077
|
const runningTaskInstances = /* @__PURE__ */ new Map();
|
|
4078
|
+
context.runningTaskInstances = runningTaskInstances;
|
|
3846
4079
|
let runningControlPromise = null;
|
|
3847
4080
|
let stopRequested = false;
|
|
3848
4081
|
let stopAllowanceMs = Number(context.stopAllowanceMs) > 0 ? Number(context.stopAllowanceMs) : 6e4;
|
|
@@ -4203,7 +4436,9 @@ var TasksManager = class _TasksManager {
|
|
|
4203
4436
|
SERVICE_TASK_NAMES,
|
|
4204
4437
|
TaskGetLogs,
|
|
4205
4438
|
TaskPauseRunner,
|
|
4439
|
+
TaskPauseTask,
|
|
4206
4440
|
TaskPing,
|
|
4441
|
+
TaskResumeTask,
|
|
4207
4442
|
TaskSampleProcess,
|
|
4208
4443
|
TaskSetRuntimeParam,
|
|
4209
4444
|
TaskShellCommand,
|
|
@@ -4214,6 +4449,8 @@ var TasksManager = class _TasksManager {
|
|
|
4214
4449
|
TasksManager,
|
|
4215
4450
|
TasksRegistry,
|
|
4216
4451
|
appendTaskIpcLog,
|
|
4452
|
+
applyPauseTask,
|
|
4453
|
+
applyResumeTask,
|
|
4217
4454
|
applyRunnerPaused,
|
|
4218
4455
|
applyRuntimeParam,
|
|
4219
4456
|
applyRuntimePatch,
|