@nmakarov/cli-toolkit 0.69.0 → 0.71.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/tasks.js CHANGED
@@ -342,12 +342,13 @@ function tasksSchemaSpec(queueName = "tasks") {
342
342
  }
343
343
  };
344
344
  }
345
- function taskHistoryInsertFromQueueRow(row, overrides) {
345
+ function taskHistoryInsertFromQueueRow(row, overrides = {}) {
346
346
  const { id, ...snapshot } = row;
347
- void id;
347
+ const opid = overrides.opid !== void 0 ? overrides.opid : snapshot.opid != null && String(snapshot.opid).trim() !== "" ? snapshot.opid : id;
348
348
  return {
349
349
  ...snapshot,
350
- ...overrides
350
+ ...overrides,
351
+ opid
351
352
  };
352
353
  }
353
354
  async function ensureTaskTables(context, options = {}) {
@@ -2686,69 +2687,6 @@ var TaskStopRunner = class extends AbstractTask {
2686
2687
  }
2687
2688
  };
2688
2689
 
2689
- // src/tasks/coreTasks/TaskGetLogs.js
2690
- var TaskGetLogs = class extends AbstractTask {
2691
- /**
2692
- * @param {object} context
2693
- * @param {Record<string, unknown>} [overrides]
2694
- * @returns {Promise<{ source: string, resource: string, tail: number, afterTs?: string }>}
2695
- */
2696
- static async resolveCustomParams(context, overrides = {}) {
2697
- const merged = AbstractTask._mergeTypedParams(context, "task-get-logs", {
2698
- source: "string",
2699
- resource: "string",
2700
- tail: "number default 100",
2701
- afterTs: "string"
2702
- }, overrides);
2703
- const source = typeof merged.source === "string" ? merged.source.trim() : "";
2704
- const resource = typeof merged.resource === "string" ? merged.resource.trim() : "";
2705
- if (!source) throw new ParamError('getLogs: param "source" is required');
2706
- if (!resource) throw new ParamError('getLogs: param "resource" is required');
2707
- let tail = Number(merged.tail);
2708
- if (!Number.isFinite(tail) || tail < 1) tail = 100;
2709
- tail = Math.min(1e4, Math.max(1, Math.floor(tail)));
2710
- const out = { source, resource, tail };
2711
- if (typeof merged.afterTs === "string" && merged.afterTs.trim()) {
2712
- out.afterTs = merged.afterTs.trim();
2713
- }
2714
- return out;
2715
- }
2716
- /**
2717
- * @param {unknown} _reportProgress Unused (single-shot read, no progress events).
2718
- * @returns {Promise<{ success: boolean, results: unknown }>}
2719
- */
2720
- async run(_reportProgress) {
2721
- const p = this.task.params ?? {};
2722
- const source = String(p.source ?? "").trim();
2723
- const resource = String(p.resource ?? "").trim();
2724
- const tail = Math.max(1, Math.min(1e4, Number(p.tail) > 0 ? Number(p.tail) : 100));
2725
- const afterTs = p.afterTs != null && String(p.afterTs).trim() ? String(p.afterTs).trim() : null;
2726
- if (!source || !resource) {
2727
- return {
2728
- success: false,
2729
- results: { error: 'getLogs requires params "source" and "resource"' }
2730
- };
2731
- }
2732
- try {
2733
- const { records, latestTs } = await readTaskIpcLogsSnapshot(this.context, {
2734
- source,
2735
- resource,
2736
- tail,
2737
- afterTs
2738
- });
2739
- return {
2740
- success: true,
2741
- results: { records, latestTs, source, resource }
2742
- };
2743
- } catch (e) {
2744
- return {
2745
- success: false,
2746
- results: { error: e?.message ?? String(e) }
2747
- };
2748
- }
2749
- }
2750
- };
2751
-
2752
2690
  // src/tasks/runtimeParams.js
2753
2691
  var LOOP_RUNTIME_KEYS = ["maxParallel", "pollMs", "claimJitterMs", "scanLimit"];
2754
2692
  var LOGGER_RUNTIME_KEYS = [
@@ -2762,7 +2700,77 @@ var LOGGER_RUNTIME_KEYS = [
2762
2700
  "progressWithTimes",
2763
2701
  "progressThrottleMs"
2764
2702
  ];
2765
- var CONTROL_LANE_TASK_NAMES = ["stopRunner", "stop", "setRuntimeParam", "setRunnerParam"];
2703
+ var DEFAULT_RUNTIME_PARAM_SPECS = [
2704
+ {
2705
+ key: "maxParallel",
2706
+ type: "number",
2707
+ label: "Max parallel",
2708
+ description: "Worker-lane concurrency (how many tasks claim at once)"
2709
+ },
2710
+ {
2711
+ key: "pollMs",
2712
+ type: "number",
2713
+ label: "Poll ms",
2714
+ description: "Idle poll interval between claim attempts"
2715
+ },
2716
+ {
2717
+ key: "claimJitterMs",
2718
+ type: "number",
2719
+ label: "Claim jitter ms",
2720
+ description: "Random delay before worker claims (0 = off)"
2721
+ },
2722
+ {
2723
+ key: "scanLimit",
2724
+ type: "number",
2725
+ label: "Scan limit",
2726
+ description: "Max idle rows scanned per claim attempt"
2727
+ }
2728
+ ];
2729
+ function mergeRuntimeParamSpecs(extra) {
2730
+ const byKey = new Map(DEFAULT_RUNTIME_PARAM_SPECS.map((s) => [s.key, { ...s }]));
2731
+ if (Array.isArray(extra)) {
2732
+ for (const raw of extra) {
2733
+ if (!raw || typeof raw !== "object") continue;
2734
+ const key = String(raw.key ?? "").trim();
2735
+ if (!key) continue;
2736
+ const prev = byKey.get(key) ?? {};
2737
+ const type = ["number", "boolean", "string"].includes(raw.type) ? raw.type : prev.type ?? "string";
2738
+ byKey.set(key, {
2739
+ key,
2740
+ type,
2741
+ label: String(raw.label ?? prev.label ?? key),
2742
+ description: raw.description != null ? String(raw.description) : prev.description != null ? String(prev.description) : void 0
2743
+ });
2744
+ }
2745
+ }
2746
+ return Array.from(byKey.values());
2747
+ }
2748
+ function runtimeValuesForSpecs(context, specs = DEFAULT_RUNTIME_PARAM_SPECS) {
2749
+ const rt = ensureTasksRuntime(context);
2750
+ const out = {};
2751
+ for (const s of specs) {
2752
+ if (rt[s.key] !== void 0) out[s.key] = rt[s.key];
2753
+ }
2754
+ return out;
2755
+ }
2756
+ function runtimeParamSpecsFromMetadata(metadata) {
2757
+ const meta = metadata && typeof metadata === "object" ? metadata : null;
2758
+ const raw = meta?.runtimeParams;
2759
+ if (!Array.isArray(raw) || raw.length === 0) {
2760
+ return mergeRuntimeParamSpecs();
2761
+ }
2762
+ return mergeRuntimeParamSpecs(raw);
2763
+ }
2764
+ var CONTROL_LANE_TASK_NAMES = [
2765
+ "stopRunner",
2766
+ "stop",
2767
+ "pauseRunner",
2768
+ "pause",
2769
+ "unpauseRunner",
2770
+ "unpause",
2771
+ "setRuntimeParam",
2772
+ "setRunnerParam"
2773
+ ];
2766
2774
  function controlLaneTaskNames(extra) {
2767
2775
  const names = [...CONTROL_LANE_TASK_NAMES];
2768
2776
  if (extra == null || extra === "") return names;
@@ -2825,6 +2833,7 @@ function ensureTasksRuntime(context, seed = {}) {
2825
2833
  if (rt.pollMs === void 0) rt.pollMs = seed.pollMs ?? 1e3;
2826
2834
  if (rt.claimJitterMs === void 0) rt.claimJitterMs = seed.claimJitterMs ?? 0;
2827
2835
  if (rt.scanLimit === void 0) rt.scanLimit = seed.scanLimit ?? 100;
2836
+ if (rt.paused === void 0) rt.paused = seed.paused === true;
2828
2837
  return rt;
2829
2838
  }
2830
2839
  async function applyRuntimeParam(context, key, value) {
@@ -2848,12 +2857,15 @@ async function applyRuntimeParam(context, key, value) {
2848
2857
  const reg = context.servicesRegistry;
2849
2858
  if (reg?.rowId && reg?.registryTable) {
2850
2859
  try {
2851
- const loopSnapshot = {};
2860
+ const specs = Array.isArray(context.tasksRuntimeParamSpecs) ? context.tasksRuntimeParamSpecs : DEFAULT_RUNTIME_PARAM_SPECS;
2861
+ const runtimeSnapshot = runtimeValuesForSpecs(context, specs);
2852
2862
  for (const lk of LOOP_RUNTIME_KEYS) {
2853
- if (runtime[lk] !== void 0) loopSnapshot[lk] = runtime[lk];
2863
+ if (runtime[lk] !== void 0 && runtimeSnapshot[lk] === void 0) {
2864
+ runtimeSnapshot[lk] = runtime[lk];
2865
+ }
2854
2866
  }
2855
2867
  await updateServicesRegistryMetadata(context, reg, {
2856
- runtime: loopSnapshot,
2868
+ runtime: runtimeSnapshot,
2857
2869
  runtimeUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
2858
2870
  });
2859
2871
  applied.push("servicesRegistry");
@@ -2889,6 +2901,140 @@ function readLoopRuntime(context) {
2889
2901
  };
2890
2902
  }
2891
2903
 
2904
+ // src/tasks/coreTasks/TaskPauseRunner.js
2905
+ async function applyRunnerPaused(context, paused) {
2906
+ const runtime = ensureTasksRuntime(context);
2907
+ const was = runtime.paused === true;
2908
+ runtime.paused = paused === true;
2909
+ const registry = context.servicesRegistry;
2910
+ if (registry && typeof registry === "object") {
2911
+ await updateServicesRegistryMetadata(context, registry, {
2912
+ paused: runtime.paused,
2913
+ pausedAt: runtime.paused ? (/* @__PURE__ */ new Date()).toISOString() : null
2914
+ });
2915
+ }
2916
+ const message = runtime.paused ? was ? "Runner already paused (no new worker tasks)." : "Runner paused: finishing in-flight work; no new worker tasks until unpause." : was ? "Runner unpaused: claiming worker tasks again." : "Runner already running (not paused).";
2917
+ context.logger?.warn?.(
2918
+ runtime.paused ? `[TaskPauseRunner] ${message}` : `[TaskUnpauseRunner] ${message}`
2919
+ );
2920
+ return {
2921
+ success: true,
2922
+ results: {
2923
+ paused: runtime.paused,
2924
+ message
2925
+ }
2926
+ };
2927
+ }
2928
+ var TaskPauseRunner = class extends AbstractTask {
2929
+ static taskName = "pauseRunner";
2930
+ static description = "Pause a runner: finish in-flight tasks, claim no new worker tasks until unpaused";
2931
+ static aliases = ["pause"];
2932
+ static defaultWaitForResult = true;
2933
+ /**
2934
+ * @param {object} context
2935
+ * @param {Record<string, unknown>} [overrides]
2936
+ * @returns {Promise<object>}
2937
+ */
2938
+ static async resolveParams(context, overrides = {}) {
2939
+ const main = await super.resolveParams(context, overrides);
2940
+ if (!main.serviceName) {
2941
+ throw new ParamError(
2942
+ "pause/pauseRunner requires --serviceName (registry instance name; optional --serviceGroup, --instanceNumber, --serverName to narrow targeting)"
2943
+ );
2944
+ }
2945
+ return main;
2946
+ }
2947
+ async run() {
2948
+ return applyRunnerPaused(this.context, true);
2949
+ }
2950
+ };
2951
+ var TaskUnpauseRunner = class extends AbstractTask {
2952
+ static taskName = "unpauseRunner";
2953
+ static description = "Unpause a runner: resume claiming worker tasks";
2954
+ static aliases = ["unpause"];
2955
+ static defaultWaitForResult = true;
2956
+ /**
2957
+ * @param {object} context
2958
+ * @param {Record<string, unknown>} [overrides]
2959
+ * @returns {Promise<object>}
2960
+ */
2961
+ static async resolveParams(context, overrides = {}) {
2962
+ const main = await super.resolveParams(context, overrides);
2963
+ if (!main.serviceName) {
2964
+ throw new ParamError(
2965
+ "unpause/unpauseRunner requires --serviceName (registry instance name; optional --serviceGroup, --instanceNumber, --serverName to narrow targeting)"
2966
+ );
2967
+ }
2968
+ return main;
2969
+ }
2970
+ async run() {
2971
+ return applyRunnerPaused(this.context, false);
2972
+ }
2973
+ };
2974
+
2975
+ // src/tasks/coreTasks/TaskGetLogs.js
2976
+ var TaskGetLogs = class extends AbstractTask {
2977
+ /**
2978
+ * @param {object} context
2979
+ * @param {Record<string, unknown>} [overrides]
2980
+ * @returns {Promise<{ source: string, resource: string, tail: number, afterTs?: string }>}
2981
+ */
2982
+ static async resolveCustomParams(context, overrides = {}) {
2983
+ const merged = AbstractTask._mergeTypedParams(context, "task-get-logs", {
2984
+ source: "string",
2985
+ resource: "string",
2986
+ tail: "number default 100",
2987
+ afterTs: "string"
2988
+ }, overrides);
2989
+ const source = typeof merged.source === "string" ? merged.source.trim() : "";
2990
+ const resource = typeof merged.resource === "string" ? merged.resource.trim() : "";
2991
+ if (!source) throw new ParamError('getLogs: param "source" is required');
2992
+ if (!resource) throw new ParamError('getLogs: param "resource" is required');
2993
+ let tail = Number(merged.tail);
2994
+ if (!Number.isFinite(tail) || tail < 1) tail = 100;
2995
+ tail = Math.min(1e4, Math.max(1, Math.floor(tail)));
2996
+ const out = { source, resource, tail };
2997
+ if (typeof merged.afterTs === "string" && merged.afterTs.trim()) {
2998
+ out.afterTs = merged.afterTs.trim();
2999
+ }
3000
+ return out;
3001
+ }
3002
+ /**
3003
+ * @param {unknown} _reportProgress Unused (single-shot read, no progress events).
3004
+ * @returns {Promise<{ success: boolean, results: unknown }>}
3005
+ */
3006
+ async run(_reportProgress) {
3007
+ const p = this.task.params ?? {};
3008
+ const source = String(p.source ?? "").trim();
3009
+ const resource = String(p.resource ?? "").trim();
3010
+ const tail = Math.max(1, Math.min(1e4, Number(p.tail) > 0 ? Number(p.tail) : 100));
3011
+ const afterTs = p.afterTs != null && String(p.afterTs).trim() ? String(p.afterTs).trim() : null;
3012
+ if (!source || !resource) {
3013
+ return {
3014
+ success: false,
3015
+ results: { error: 'getLogs requires params "source" and "resource"' }
3016
+ };
3017
+ }
3018
+ try {
3019
+ const { records, latestTs } = await readTaskIpcLogsSnapshot(this.context, {
3020
+ source,
3021
+ resource,
3022
+ tail,
3023
+ afterTs
3024
+ });
3025
+ return {
3026
+ success: true,
3027
+ results: { records, latestTs, source, resource }
3028
+ };
3029
+ } catch (e) {
3030
+ return {
3031
+ success: false,
3032
+ results: { error: e?.message ?? String(e) }
3033
+ };
3034
+ }
3035
+ }
3036
+ };
3037
+
2892
3038
  // src/tasks/coreTasks/TaskSetRuntimeParam.js
2893
3039
  var TaskSetRuntimeParam = class extends AbstractTask {
2894
3040
  static defaultWaitForResult = true;
@@ -3044,7 +3190,7 @@ var TasksRegistry = class _TasksRegistry {
3044
3190
  * @returns {TasksRegistry}
3045
3191
  */
3046
3192
  static withCoreTasks() {
3047
- 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);
3193
+ 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);
3048
3194
  }
3049
3195
  /**
3050
3196
  * Register a single task class under a name. Overwrites any previous entry.
@@ -3147,6 +3293,10 @@ var SERVICE_TASK_NAMES = [
3147
3293
  "ping",
3148
3294
  "stop",
3149
3295
  "stopRunner",
3296
+ "pause",
3297
+ "pauseRunner",
3298
+ "unpause",
3299
+ "unpauseRunner",
3150
3300
  "shellCommand",
3151
3301
  "systemInfo",
3152
3302
  "info",
@@ -3608,17 +3758,25 @@ async function runTasksLoop(context, options) {
3608
3758
  if (hbGroup) {
3609
3759
  const hbIntervalMs = options.runnerHeartbeatIntervalMs ?? 1e4;
3610
3760
  const staleMs = options.runnerHeartbeatStaleMs ?? 45e3;
3611
- const loop0 = readLoopRuntime(context);
3761
+ const runtimeParamSpecs = mergeRuntimeParamSpecs(options.runnerRuntimeParams);
3762
+ context.tasksRuntimeParamSpecs = runtimeParamSpecs;
3612
3763
  const defaultMeta = {
3613
3764
  component: "tasks-runner",
3614
3765
  allowedTasks: allowedTasks?.length ? allowedTasks.join(",") : "all",
3615
- runtime: {
3616
- maxParallel: loop0.maxParallel,
3617
- pollMs: loop0.pollMs,
3618
- claimJitterMs: loop0.claimJitterMs,
3619
- scanLimit: loop0.scanLimit
3620
- }
3766
+ paused: false,
3767
+ runtimeParams: runtimeParamSpecs,
3768
+ runtime: runtimeValuesForSpecs(context, runtimeParamSpecs)
3621
3769
  };
3770
+ const metadata = {
3771
+ ...defaultMeta,
3772
+ ...options.runnerMetadata && typeof options.runnerMetadata === "object" ? options.runnerMetadata : {}
3773
+ };
3774
+ if (!Array.isArray(metadata.runtimeParams) || metadata.runtimeParams.length === 0) {
3775
+ metadata.runtimeParams = defaultMeta.runtimeParams;
3776
+ }
3777
+ if (!metadata.runtime || typeof metadata.runtime !== "object") {
3778
+ metadata.runtime = defaultMeta.runtime;
3779
+ }
3622
3780
  registryReg = await registerInServicesRegistry(context, {
3623
3781
  queueName,
3624
3782
  target,
@@ -3628,7 +3786,7 @@ async function runTasksLoop(context, options) {
3628
3786
  staleMs,
3629
3787
  groupMaxInstances: options.runnerGroupMaxInstances,
3630
3788
  enforceMaxInstances: options.runnerEnforceMaxInstances ?? true,
3631
- metadata: options.runnerMetadata ?? defaultMeta
3789
+ metadata
3632
3790
  });
3633
3791
  context.servicesRegistry = registryReg;
3634
3792
  runnerIdentity = {
@@ -3678,28 +3836,38 @@ async function runTasksLoop(context, options) {
3678
3836
  if (claimJitterMs > 0) {
3679
3837
  await sleepMs(Math.floor(Math.random() * (claimJitterMs + 1)));
3680
3838
  }
3681
- while (runningPromises.size < maxParallel) {
3682
- const claimed = await claimNextRunnableTask(
3683
- context,
3684
- tasksTable,
3685
- target,
3686
- registry,
3687
- scanLimit,
3688
- allowedTasks,
3689
- runnerIdentity
3690
- );
3691
- if (!claimed) break;
3692
- const p = executeClaimedTask(context, tasksTable, historyTable, claimed, registry, runningTaskInstances).then(async (outcome) => {
3693
- if (outcome.stopRunnerRequested && !stopRequested) {
3694
- stopRequested = true;
3695
- stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;
3696
- context.tasksRunnerStop = true;
3697
- await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
3698
- }
3699
- }).finally(() => {
3700
- runningPromises.delete(p);
3701
- });
3702
- runningPromises.add(p);
3839
+ const paused = context.tasksRuntime?.paused === true;
3840
+ if (!paused) {
3841
+ while (runningPromises.size < maxParallel) {
3842
+ const claimed = await claimNextRunnableTask(
3843
+ context,
3844
+ tasksTable,
3845
+ target,
3846
+ registry,
3847
+ scanLimit,
3848
+ allowedTasks,
3849
+ runnerIdentity
3850
+ );
3851
+ if (!claimed) break;
3852
+ const p = executeClaimedTask(
3853
+ context,
3854
+ tasksTable,
3855
+ historyTable,
3856
+ claimed,
3857
+ registry,
3858
+ runningTaskInstances
3859
+ ).then(async (outcome) => {
3860
+ if (outcome.stopRunnerRequested && !stopRequested) {
3861
+ stopRequested = true;
3862
+ stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;
3863
+ context.tasksRunnerStop = true;
3864
+ await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
3865
+ }
3866
+ }).finally(() => {
3867
+ runningPromises.delete(p);
3868
+ });
3869
+ runningPromises.add(p);
3870
+ }
3703
3871
  }
3704
3872
  const wakePromises = [...runningPromises];
3705
3873
  if (runningControlPromise) {
@@ -3753,16 +3921,26 @@ async function waitForTaskResult(context, taskId, options = {}) {
3753
3921
  const pollMs = options.pollMs ?? 500;
3754
3922
  const { tasksTable, historyTable } = queueToTableNames(queueName);
3755
3923
  const deadline = Date.now() + timeoutMs;
3756
- const waitStartedAt = /* @__PURE__ */ new Date();
3757
- let cachedNameOpid = null;
3758
- async function historySinceWait(name, opid) {
3759
- let q = db(historyTable).where({ name }).where("completed_at", ">=", waitStartedAt);
3924
+ const waitStartedAt = new Date(Date.now() - 5e3);
3925
+ let cachedNameOpid = options.name != null && String(options.name).trim() !== "" ? {
3926
+ name: String(options.name).trim(),
3927
+ opid: options.opid !== void 0 ? options.opid : null
3928
+ } : null;
3929
+ async function findHistory(name, opid) {
3930
+ const base = () => db(historyTable).where({ name }).where("completed_at", ">=", waitStartedAt);
3931
+ if (opid != null && String(opid).trim() !== "") {
3932
+ const byOpid = await base().where({ opid }).orderBy("completed_at", "desc").first();
3933
+ if (byOpid) return byOpid;
3934
+ }
3935
+ const byQueueId = await base().where({ opid: taskId }).orderBy("completed_at", "desc").first();
3936
+ if (byQueueId) return byQueueId;
3937
+ const byQueueIdAny = await db(historyTable).where({ name, opid: taskId }).orderBy("completed_at", "desc").first();
3938
+ if (byQueueIdAny) return byQueueIdAny;
3760
3939
  if (opid == null || opid === "") {
3761
- q = q.whereNull("opid");
3762
- } else {
3763
- q = q.where({ opid });
3940
+ const byNull = await base().whereNull("opid").orderBy("completed_at", "desc").first();
3941
+ if (byNull) return byNull;
3764
3942
  }
3765
- return await q.orderBy("completed_at", "desc").first();
3943
+ return void 0;
3766
3944
  }
3767
3945
  while (Date.now() <= deadline) {
3768
3946
  const legacy = await db(historyTable).where({ id: taskId }).orderBy("created_at", "desc").first();
@@ -3772,18 +3950,17 @@ async function waitForTaskResult(context, taskId, options = {}) {
3772
3950
  const pending = await db(tasksTable).where({ id: taskId }).first();
3773
3951
  if (pending) {
3774
3952
  cachedNameOpid = { name: pending.name, opid: pending.opid };
3775
- const done = await historySinceWait(pending.name, pending.opid);
3776
- if (done) {
3777
- return done;
3778
- }
3779
- } else if (cachedNameOpid) {
3780
- const done = await historySinceWait(cachedNameOpid.name, cachedNameOpid.opid);
3953
+ }
3954
+ if (cachedNameOpid) {
3955
+ const done = await findHistory(cachedNameOpid.name, cachedNameOpid.opid);
3781
3956
  if (done) {
3782
3957
  return done;
3783
3958
  }
3784
- return null;
3785
3959
  } else {
3786
- return null;
3960
+ const byQueueId = await db(historyTable).where({ opid: taskId }).orderBy("completed_at", "desc").first();
3961
+ if (byQueueId) {
3962
+ return byQueueId;
3963
+ }
3787
3964
  }
3788
3965
  await sleepMs(pollMs);
3789
3966
  }
@@ -3923,10 +4100,12 @@ var TasksManager = class _TasksManager {
3923
4100
  };
3924
4101
  export {
3925
4102
  AbstractTask,
4103
+ DEFAULT_RUNTIME_PARAM_SPECS,
3926
4104
  LOGGER_RUNTIME_KEYS,
3927
4105
  LOOP_RUNTIME_KEYS,
3928
4106
  SERVICE_TASK_NAMES,
3929
4107
  TaskGetLogs,
4108
+ TaskPauseRunner,
3930
4109
  TaskPing,
3931
4110
  TaskSampleProcess,
3932
4111
  TaskSetRuntimeParam,
@@ -3934,9 +4113,11 @@ export {
3934
4113
  TaskStopRunner,
3935
4114
  TaskSumAB,
3936
4115
  TaskSystemInfo,
4116
+ TaskUnpauseRunner,
3937
4117
  TasksManager,
3938
4118
  TasksRegistry,
3939
4119
  appendTaskIpcLog,
4120
+ applyRunnerPaused,
3940
4121
  applyRuntimeParam,
3941
4122
  applyRuntimePatch,
3942
4123
  coerceRuntimeValue,
@@ -3954,6 +4135,7 @@ export {
3954
4135
  listServicesRegistry,
3955
4136
  matchesParsedPattern,
3956
4137
  mergeAllowedTasksWithServiceTasks,
4138
+ mergeRuntimeParamSpecs,
3957
4139
  nextTimeMatch,
3958
4140
  normalizeAllowedTasks,
3959
4141
  queueToTableNames,
@@ -3967,6 +4149,8 @@ export {
3967
4149
  resolveSteps,
3968
4150
  runNodeTaskScript,
3969
4151
  runTasksLoop,
4152
+ runtimeParamSpecsFromMetadata,
4153
+ runtimeValuesForSpecs,
3970
4154
  taskHistoryInsertFromQueueRow,
3971
4155
  timeMatcher,
3972
4156
  touchServicesRegistry as touchRunnerHeartbeat,