@apisurf/ngn-core 0.2.8 → 0.3.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/core.d.ts +18 -2
- package/dist/core.js +23 -2
- package/package.json +4 -4
package/dist/core.d.ts
CHANGED
|
@@ -607,6 +607,8 @@ interface ExecuteSchedule {
|
|
|
607
607
|
/** When the next tick is due, epoch ms. */
|
|
608
608
|
nextAt?: number | null;
|
|
609
609
|
}
|
|
610
|
+
/** The `task_runs.id` of the run that threw `error`, when a task run did. */
|
|
611
|
+
declare function failedRunId(error: unknown): number | null;
|
|
610
612
|
declare class Task {
|
|
611
613
|
private taskCallbacks;
|
|
612
614
|
private startRun;
|
|
@@ -703,12 +705,26 @@ declare class TaskLibrary {
|
|
|
703
705
|
|
|
704
706
|
type Options$1 = {
|
|
705
707
|
taskLibrary: TaskLibrary;
|
|
708
|
+
/** Called when a scheduled run throws, with the run it was recorded as when there is one. */
|
|
709
|
+
onRunError?: (path: string, error: unknown, runId: number | null) => void;
|
|
706
710
|
};
|
|
711
|
+
/** What `start()` did with each task: scheduled on its pattern, or left out and why. */
|
|
712
|
+
interface ScheduleReport {
|
|
713
|
+
scheduled: {
|
|
714
|
+
path: string;
|
|
715
|
+
pattern: string;
|
|
716
|
+
}[];
|
|
717
|
+
failed: {
|
|
718
|
+
path: string;
|
|
719
|
+
reason: string;
|
|
720
|
+
}[];
|
|
721
|
+
}
|
|
707
722
|
declare class TaskLibraryScheduler {
|
|
708
723
|
private taskLibrary;
|
|
724
|
+
private onRunError;
|
|
709
725
|
private scheduledTasks;
|
|
710
726
|
constructor(options: Options$1);
|
|
711
|
-
start(): Promise<
|
|
727
|
+
start(): Promise<ScheduleReport>;
|
|
712
728
|
stop(): Promise<void>;
|
|
713
729
|
scheduleTask(task: Task): Promise<void>;
|
|
714
730
|
unscheduleTask(task: Task): void;
|
|
@@ -739,4 +755,4 @@ declare function createControlsGenerator({ dbClient, env, }: {
|
|
|
739
755
|
env: TaskContext["env"];
|
|
740
756
|
}): BuildCompiledTaskConfigFn;
|
|
741
757
|
|
|
742
|
-
export { type AddJob, type Backoff, type ClaimOptions, Compiler, type DBInstance, type Duration, type InitDBOptions, type Job, type JobFilter, type JobStatus, LockBusyError, type LockOptions, type Migration, type OverlapPolicy, Queue, type QueueOptions, type QueueStats, Task, type TaskContext, TaskLibrary, TaskLibraryScheduler, TaskOnceRunner, type TaskRun, type TaskSqlite, type WorkHandler, type WorkOptions, type WorkSummary, type WorkerHandle, closeTaskDatabases, createControlsGenerator, executeEsm, getDbClient, isCronPatternValid, scheduleTask, setupDbClient };
|
|
758
|
+
export { type AddJob, type Backoff, type ClaimOptions, Compiler, type DBInstance, type Duration, type InitDBOptions, type Job, type JobFilter, type JobStatus, LockBusyError, type LockOptions, type Migration, type OverlapPolicy, Queue, type QueueOptions, type QueueStats, type ScheduleReport, Task, type TaskContext, TaskLibrary, TaskLibraryScheduler, TaskOnceRunner, type TaskRun, type TaskSqlite, type WorkHandler, type WorkOptions, type WorkSummary, type WorkerHandle, closeTaskDatabases, createControlsGenerator, executeEsm, failedRunId, getDbClient, isCronPatternValid, scheduleTask, setupDbClient };
|
package/dist/core.js
CHANGED
|
@@ -1170,6 +1170,10 @@ function breakerSkips(failedInARow, breaker) {
|
|
|
1170
1170
|
|
|
1171
1171
|
// src/runtime/task.ts
|
|
1172
1172
|
var sleep2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1173
|
+
var failedRuns = /* @__PURE__ */ new WeakMap();
|
|
1174
|
+
function failedRunId(error) {
|
|
1175
|
+
return error && typeof error === "object" ? failedRuns.get(error) ?? null : null;
|
|
1176
|
+
}
|
|
1173
1177
|
var Task = class {
|
|
1174
1178
|
taskCallbacks;
|
|
1175
1179
|
startRun;
|
|
@@ -1304,6 +1308,7 @@ var Task = class {
|
|
|
1304
1308
|
await hooks.onSuccess?.(taskContext);
|
|
1305
1309
|
return taskReturnValue;
|
|
1306
1310
|
} catch (err) {
|
|
1311
|
+
if (err && typeof err === "object") failedRuns.set(err, run.id);
|
|
1307
1312
|
await run.callbacks.onFailure?.({ path });
|
|
1308
1313
|
await hooks.onError?.(err, taskContext);
|
|
1309
1314
|
throw err;
|
|
@@ -1553,23 +1558,30 @@ function scheduleTask(task, pattern, onError) {
|
|
|
1553
1558
|
// src/runtime/taskLibraryScheduler.ts
|
|
1554
1559
|
var TaskLibraryScheduler = class {
|
|
1555
1560
|
taskLibrary;
|
|
1561
|
+
onRunError;
|
|
1556
1562
|
scheduledTasks = /* @__PURE__ */ new Map();
|
|
1557
1563
|
constructor(options) {
|
|
1558
1564
|
this.taskLibrary = options.taskLibrary;
|
|
1565
|
+
this.onRunError = options.onRunError;
|
|
1559
1566
|
}
|
|
1560
1567
|
async start() {
|
|
1561
1568
|
logTaskLibraryScheduler("Starting scheduler");
|
|
1569
|
+
const report = { scheduled: [], failed: [] };
|
|
1562
1570
|
const scheduledTasks = this.taskLibrary.getTasks().map(async (task) => {
|
|
1563
1571
|
try {
|
|
1564
|
-
|
|
1565
|
-
|
|
1572
|
+
await this.scheduleTask(task);
|
|
1573
|
+
report.scheduled.push({ path: task.taskPath, pattern: task.timingPattern ?? "" });
|
|
1566
1574
|
} catch (error) {
|
|
1567
1575
|
logTaskLibrarySchedulerError(`Error scheduling task: ${task.taskPath}`);
|
|
1568
1576
|
logTaskLibrarySchedulerError(error);
|
|
1577
|
+
report.failed.push({ path: task.taskPath, reason: reasonOf(error, task.taskPath) });
|
|
1569
1578
|
}
|
|
1570
1579
|
});
|
|
1571
1580
|
await Promise.all(scheduledTasks);
|
|
1572
1581
|
logTaskLibraryScheduler("Scheduler started");
|
|
1582
|
+
report.scheduled.sort(byPath);
|
|
1583
|
+
report.failed.sort(byPath);
|
|
1584
|
+
return report;
|
|
1573
1585
|
}
|
|
1574
1586
|
async stop() {
|
|
1575
1587
|
logTaskLibraryScheduler("Stopping scheduler");
|
|
@@ -1591,6 +1603,7 @@ var TaskLibraryScheduler = class {
|
|
|
1591
1603
|
const scheduledTask = scheduleTask(task, task.timingPattern, (error) => {
|
|
1592
1604
|
logTaskLibrarySchedulerError(`Run failed: ${task.taskPath}`);
|
|
1593
1605
|
logTaskLibrarySchedulerError(error);
|
|
1606
|
+
this.onRunError?.(task.taskPath, error, failedRunId(error));
|
|
1594
1607
|
});
|
|
1595
1608
|
this.scheduledTasks.set(task.taskPath, scheduledTask);
|
|
1596
1609
|
logTaskLibraryScheduler(`Scheduled: ${task.taskPath}`);
|
|
@@ -1623,6 +1636,13 @@ var TaskLibraryScheduler = class {
|
|
|
1623
1636
|
// task.stop();
|
|
1624
1637
|
// }
|
|
1625
1638
|
};
|
|
1639
|
+
function byPath(a, b) {
|
|
1640
|
+
return a.path.localeCompare(b.path);
|
|
1641
|
+
}
|
|
1642
|
+
function reasonOf(error, path) {
|
|
1643
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1644
|
+
return message.replace(/^Invariant failed: /, "").replace(` for ${path}`, "").replace(`: ${path}`, "");
|
|
1645
|
+
}
|
|
1626
1646
|
|
|
1627
1647
|
// src/runtime/taskOnceRunner.ts
|
|
1628
1648
|
import invariant9 from "tiny-invariant";
|
|
@@ -2209,6 +2229,7 @@ export {
|
|
|
2209
2229
|
closeTaskDatabases,
|
|
2210
2230
|
createControlsGenerator,
|
|
2211
2231
|
executeEsm,
|
|
2232
|
+
failedRunId,
|
|
2212
2233
|
getDbClient,
|
|
2213
2234
|
initDbFileIfNotExists,
|
|
2214
2235
|
isCronPatternValid,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apisurf/ngn-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "ngn runtime: task compilation, scheduling and the run/log/timing services.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Luka Vidakovic",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"esbuild": "^0.27.1",
|
|
39
39
|
"tiny-invariant": "^1.3.3",
|
|
40
40
|
"zod": "^3.24.2",
|
|
41
|
-
"@apisurf/ngn-os": "0.
|
|
42
|
-
"@apisurf/ngn-persistence": "0.
|
|
43
|
-
"@apisurf/ngn-schema": "0.
|
|
41
|
+
"@apisurf/ngn-os": "0.3.0",
|
|
42
|
+
"@apisurf/ngn-persistence": "0.3.0",
|
|
43
|
+
"@apisurf/ngn-schema": "0.3.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^22.8.1",
|