@karmaniverous/jeeves-runner 0.6.0 → 0.7.1
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/jeeves-runner/index.js +38 -29
- package/dist/mjs/index.js +38 -29
- package/package.json +3 -3
|
@@ -3,6 +3,7 @@ import { mkdirSync, mkdtempSync, writeFileSync, unlinkSync, existsSync, readFile
|
|
|
3
3
|
import { dirname, join, extname, resolve } from 'node:path';
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import { DatabaseSync } from 'node:sqlite';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
6
7
|
import { pino } from 'pino';
|
|
7
8
|
import Fastify from 'fastify';
|
|
8
9
|
import { createConfigQueryHandler } from '@karmaniverous/jeeves';
|
|
@@ -608,13 +609,31 @@ function registerStateRoutes(app, deps) {
|
|
|
608
609
|
* Register all API routes on the Fastify instance.
|
|
609
610
|
*/
|
|
610
611
|
function registerRoutes(app, deps) {
|
|
611
|
-
const { db, scheduler, getConfig } = deps;
|
|
612
|
-
/** GET /
|
|
613
|
-
app.get('/
|
|
612
|
+
const { db, scheduler, getConfig, version } = deps;
|
|
613
|
+
/** GET /status — Unified status endpoint (single health/metadata entrypoint). */
|
|
614
|
+
app.get('/status', () => {
|
|
615
|
+
const totalJobs = db
|
|
616
|
+
.prepare('SELECT COUNT(*) as count FROM jobs')
|
|
617
|
+
.get();
|
|
618
|
+
const runningCount = scheduler.getRunningJobs().length;
|
|
619
|
+
const failedCount = scheduler.getFailedRegistrations().length;
|
|
620
|
+
const okLastHour = db
|
|
621
|
+
.prepare(`SELECT COUNT(*) as count FROM runs
|
|
622
|
+
WHERE status = 'ok' AND started_at > datetime('now', '-1 hour')`)
|
|
623
|
+
.get();
|
|
624
|
+
const errorsLastHour = db
|
|
625
|
+
.prepare(`SELECT COUNT(*) as count FROM runs
|
|
626
|
+
WHERE status IN ('error', 'timeout') AND started_at > datetime('now', '-1 hour')`)
|
|
627
|
+
.get();
|
|
614
628
|
return {
|
|
615
|
-
|
|
629
|
+
status: 'ok',
|
|
630
|
+
version,
|
|
616
631
|
uptime: process.uptime(),
|
|
617
|
-
|
|
632
|
+
totalJobs: totalJobs.count,
|
|
633
|
+
running: runningCount,
|
|
634
|
+
failedRegistrations: failedCount,
|
|
635
|
+
okLastHour: okLastHour.count,
|
|
636
|
+
errorsLastHour: errorsLastHour.count,
|
|
618
637
|
};
|
|
619
638
|
});
|
|
620
639
|
/** GET /jobs — List all jobs with last run status. */
|
|
@@ -657,29 +676,6 @@ function registerRoutes(app, deps) {
|
|
|
657
676
|
return { error: err instanceof Error ? err.message : 'Unknown error' };
|
|
658
677
|
}
|
|
659
678
|
});
|
|
660
|
-
/** GET /stats — Aggregate job statistics. */
|
|
661
|
-
app.get('/stats', () => {
|
|
662
|
-
const totalJobs = db
|
|
663
|
-
.prepare('SELECT COUNT(*) as count FROM jobs')
|
|
664
|
-
.get();
|
|
665
|
-
const runningCount = scheduler.getRunningJobs().length;
|
|
666
|
-
const failedCount = scheduler.getFailedRegistrations().length;
|
|
667
|
-
const okLastHour = db
|
|
668
|
-
.prepare(`SELECT COUNT(*) as count FROM runs
|
|
669
|
-
WHERE status = 'ok' AND started_at > datetime('now', '-1 hour')`)
|
|
670
|
-
.get();
|
|
671
|
-
const errorsLastHour = db
|
|
672
|
-
.prepare(`SELECT COUNT(*) as count FROM runs
|
|
673
|
-
WHERE status IN ('error', 'timeout') AND started_at > datetime('now', '-1 hour')`)
|
|
674
|
-
.get();
|
|
675
|
-
return {
|
|
676
|
-
totalJobs: totalJobs.count,
|
|
677
|
-
running: runningCount,
|
|
678
|
-
failedRegistrations: failedCount,
|
|
679
|
-
okLastHour: okLastHour.count,
|
|
680
|
-
errorsLastHour: errorsLastHour.count,
|
|
681
|
-
};
|
|
682
|
-
});
|
|
683
679
|
/** GET /config — Query effective configuration via JSONPath. */
|
|
684
680
|
const configHandler = createConfigQueryHandler(getConfig);
|
|
685
681
|
app.get('/config', async (request, reply) => {
|
|
@@ -723,6 +719,7 @@ function createServer(deps) {
|
|
|
723
719
|
db: deps.db,
|
|
724
720
|
scheduler: deps.scheduler,
|
|
725
721
|
getConfig: deps.getConfig,
|
|
722
|
+
version: deps.version,
|
|
726
723
|
});
|
|
727
724
|
return app;
|
|
728
725
|
}
|
|
@@ -1602,11 +1599,23 @@ function createRunner(config, deps) {
|
|
|
1602
1599
|
});
|
|
1603
1600
|
scheduler.start();
|
|
1604
1601
|
logger.info('Scheduler started');
|
|
1602
|
+
// Read package version
|
|
1603
|
+
const pkgVersion = (() => {
|
|
1604
|
+
try {
|
|
1605
|
+
const dir = dirname(fileURLToPath(import.meta.url));
|
|
1606
|
+
const pkg = JSON.parse(readFileSync(resolve(dir, '..', 'package.json'), 'utf8'));
|
|
1607
|
+
return pkg.version ?? 'unknown';
|
|
1608
|
+
}
|
|
1609
|
+
catch {
|
|
1610
|
+
return 'unknown';
|
|
1611
|
+
}
|
|
1612
|
+
})();
|
|
1605
1613
|
// API server
|
|
1606
1614
|
server = createServer({
|
|
1607
1615
|
db,
|
|
1608
1616
|
scheduler,
|
|
1609
1617
|
getConfig: () => config,
|
|
1618
|
+
version: pkgVersion,
|
|
1610
1619
|
loggerConfig: { level: config.log.level, file: config.log.file },
|
|
1611
1620
|
});
|
|
1612
1621
|
await server.listen({ port: config.port, host: config.host });
|
|
@@ -1962,7 +1971,7 @@ program
|
|
|
1962
1971
|
const config = loadConfig(options.config);
|
|
1963
1972
|
void (async () => {
|
|
1964
1973
|
try {
|
|
1965
|
-
const resp = await fetch(`http://127.0.0.1:${String(config.port)}/
|
|
1974
|
+
const resp = await fetch(`http://127.0.0.1:${String(config.port)}/status`);
|
|
1966
1975
|
const stats = (await resp.json());
|
|
1967
1976
|
console.log(JSON.stringify(stats, null, 2));
|
|
1968
1977
|
}
|
package/dist/mjs/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { mkdirSync, mkdtempSync, writeFileSync, unlinkSync, existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, extname, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
3
5
|
import { pino } from 'pino';
|
|
4
6
|
import Fastify from 'fastify';
|
|
5
7
|
import { createConfigQueryHandler } from '@karmaniverous/jeeves';
|
|
6
8
|
import { RRStack } from '@karmaniverous/rrstack';
|
|
7
9
|
import { Cron } from 'croner';
|
|
8
10
|
import { JSONPath } from 'jsonpath-plus';
|
|
9
|
-
import { dirname, join, extname } from 'node:path';
|
|
10
11
|
import { DatabaseSync } from 'node:sqlite';
|
|
11
12
|
import { request as request$1 } from 'node:http';
|
|
12
13
|
import { request } from 'node:https';
|
|
@@ -562,13 +563,31 @@ function registerStateRoutes(app, deps) {
|
|
|
562
563
|
* Register all API routes on the Fastify instance.
|
|
563
564
|
*/
|
|
564
565
|
function registerRoutes(app, deps) {
|
|
565
|
-
const { db, scheduler, getConfig } = deps;
|
|
566
|
-
/** GET /
|
|
567
|
-
app.get('/
|
|
566
|
+
const { db, scheduler, getConfig, version } = deps;
|
|
567
|
+
/** GET /status — Unified status endpoint (single health/metadata entrypoint). */
|
|
568
|
+
app.get('/status', () => {
|
|
569
|
+
const totalJobs = db
|
|
570
|
+
.prepare('SELECT COUNT(*) as count FROM jobs')
|
|
571
|
+
.get();
|
|
572
|
+
const runningCount = scheduler.getRunningJobs().length;
|
|
573
|
+
const failedCount = scheduler.getFailedRegistrations().length;
|
|
574
|
+
const okLastHour = db
|
|
575
|
+
.prepare(`SELECT COUNT(*) as count FROM runs
|
|
576
|
+
WHERE status = 'ok' AND started_at > datetime('now', '-1 hour')`)
|
|
577
|
+
.get();
|
|
578
|
+
const errorsLastHour = db
|
|
579
|
+
.prepare(`SELECT COUNT(*) as count FROM runs
|
|
580
|
+
WHERE status IN ('error', 'timeout') AND started_at > datetime('now', '-1 hour')`)
|
|
581
|
+
.get();
|
|
568
582
|
return {
|
|
569
|
-
|
|
583
|
+
status: 'ok',
|
|
584
|
+
version,
|
|
570
585
|
uptime: process.uptime(),
|
|
571
|
-
|
|
586
|
+
totalJobs: totalJobs.count,
|
|
587
|
+
running: runningCount,
|
|
588
|
+
failedRegistrations: failedCount,
|
|
589
|
+
okLastHour: okLastHour.count,
|
|
590
|
+
errorsLastHour: errorsLastHour.count,
|
|
572
591
|
};
|
|
573
592
|
});
|
|
574
593
|
/** GET /jobs — List all jobs with last run status. */
|
|
@@ -611,29 +630,6 @@ function registerRoutes(app, deps) {
|
|
|
611
630
|
return { error: err instanceof Error ? err.message : 'Unknown error' };
|
|
612
631
|
}
|
|
613
632
|
});
|
|
614
|
-
/** GET /stats — Aggregate job statistics. */
|
|
615
|
-
app.get('/stats', () => {
|
|
616
|
-
const totalJobs = db
|
|
617
|
-
.prepare('SELECT COUNT(*) as count FROM jobs')
|
|
618
|
-
.get();
|
|
619
|
-
const runningCount = scheduler.getRunningJobs().length;
|
|
620
|
-
const failedCount = scheduler.getFailedRegistrations().length;
|
|
621
|
-
const okLastHour = db
|
|
622
|
-
.prepare(`SELECT COUNT(*) as count FROM runs
|
|
623
|
-
WHERE status = 'ok' AND started_at > datetime('now', '-1 hour')`)
|
|
624
|
-
.get();
|
|
625
|
-
const errorsLastHour = db
|
|
626
|
-
.prepare(`SELECT COUNT(*) as count FROM runs
|
|
627
|
-
WHERE status IN ('error', 'timeout') AND started_at > datetime('now', '-1 hour')`)
|
|
628
|
-
.get();
|
|
629
|
-
return {
|
|
630
|
-
totalJobs: totalJobs.count,
|
|
631
|
-
running: runningCount,
|
|
632
|
-
failedRegistrations: failedCount,
|
|
633
|
-
okLastHour: okLastHour.count,
|
|
634
|
-
errorsLastHour: errorsLastHour.count,
|
|
635
|
-
};
|
|
636
|
-
});
|
|
637
633
|
/** GET /config — Query effective configuration via JSONPath. */
|
|
638
634
|
const configHandler = createConfigQueryHandler(getConfig);
|
|
639
635
|
app.get('/config', async (request, reply) => {
|
|
@@ -677,6 +673,7 @@ function createServer(deps) {
|
|
|
677
673
|
db: deps.db,
|
|
678
674
|
scheduler: deps.scheduler,
|
|
679
675
|
getConfig: deps.getConfig,
|
|
676
|
+
version: deps.version,
|
|
680
677
|
});
|
|
681
678
|
return app;
|
|
682
679
|
}
|
|
@@ -1762,11 +1759,23 @@ function createRunner(config, deps) {
|
|
|
1762
1759
|
});
|
|
1763
1760
|
scheduler.start();
|
|
1764
1761
|
logger.info('Scheduler started');
|
|
1762
|
+
// Read package version
|
|
1763
|
+
const pkgVersion = (() => {
|
|
1764
|
+
try {
|
|
1765
|
+
const dir = dirname(fileURLToPath(import.meta.url));
|
|
1766
|
+
const pkg = JSON.parse(readFileSync(resolve(dir, '..', 'package.json'), 'utf8'));
|
|
1767
|
+
return pkg.version ?? 'unknown';
|
|
1768
|
+
}
|
|
1769
|
+
catch {
|
|
1770
|
+
return 'unknown';
|
|
1771
|
+
}
|
|
1772
|
+
})();
|
|
1765
1773
|
// API server
|
|
1766
1774
|
server = createServer({
|
|
1767
1775
|
db,
|
|
1768
1776
|
scheduler,
|
|
1769
1777
|
getConfig: () => config,
|
|
1778
|
+
version: pkgVersion,
|
|
1770
1779
|
loggerConfig: { level: config.log.level, file: config.log.file },
|
|
1771
1780
|
});
|
|
1772
1781
|
await server.listen({ port: config.port, host: config.host });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karmaniverous/jeeves-runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"author": "Jason Williscroft",
|
|
5
5
|
"description": "Graph-aware job execution engine with SQLite state. Part of the Jeeves platform.",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"node": ">=20"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@karmaniverous/jeeves": "^0.
|
|
50
|
-
"@karmaniverous/rrstack": "^0.17.
|
|
49
|
+
"@karmaniverous/jeeves": "^0.3.0",
|
|
50
|
+
"@karmaniverous/rrstack": "^0.17.1",
|
|
51
51
|
"commander": "^14.0.3",
|
|
52
52
|
"croner": "^10.0.1",
|
|
53
53
|
"fastify": "^5.7.4",
|