@nuetzliches/croniq-runner 0.1.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/CHANGELOG.md +14 -0
- package/README.md +172 -0
- package/dist/abort.d.ts +7 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +31 -0
- package/dist/abort.js.map +1 -0
- package/dist/client.d.ts +32 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +147 -0
- package/dist/client.js.map +1 -0
- package/dist/context.d.ts +82 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +52 -0
- package/dist/context.js.map +1 -0
- package/dist/deferred.d.ts +18 -0
- package/dist/deferred.d.ts.map +1 -0
- package/dist/deferred.js +40 -0
- package/dist/deferred.js.map +1 -0
- package/dist/dispatcher.d.ts +33 -0
- package/dist/dispatcher.d.ts.map +1 -0
- package/dist/dispatcher.js +159 -0
- package/dist/dispatcher.js.map +1 -0
- package/dist/duration.d.ts +2 -0
- package/dist/duration.d.ts.map +1 -0
- package/dist/duration.js +23 -0
- package/dist/duration.js.map +1 -0
- package/dist/enrichment.d.ts +15 -0
- package/dist/enrichment.d.ts.map +1 -0
- package/dist/enrichment.js +30 -0
- package/dist/enrichment.js.map +1 -0
- package/dist/handler.d.ts +35 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +47 -0
- package/dist/handler.js.map +1 -0
- package/dist/identity.d.ts +23 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +64 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/log-writer.d.ts +38 -0
- package/dist/log-writer.d.ts.map +1 -0
- package/dist/log-writer.js +153 -0
- package/dist/log-writer.js.map +1 -0
- package/dist/logger.d.ts +27 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +65 -0
- package/dist/logger.js.map +1 -0
- package/dist/options.d.ts +89 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +50 -0
- package/dist/options.js.map +1 -0
- package/dist/protocol.d.ts +54 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +8 -0
- package/dist/protocol.js.map +1 -0
- package/dist/runner.d.ts +40 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +226 -0
- package/dist/runner.js.map +1 -0
- package/dist/url.d.ts +10 -0
- package/dist/url.d.ts.map +1 -0
- package/dist/url.js +20 -0
- package/dist/url.js.map +1 -0
- package/package.json +63 -0
package/dist/runner.js
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { setMaxListeners } from 'node:events';
|
|
3
|
+
import { anySignal } from './abort.js';
|
|
4
|
+
import { CroniqClient, HttpError } from './client.js';
|
|
5
|
+
import { sleep } from './deferred.js';
|
|
6
|
+
import { ExecutionDispatcher } from './dispatcher.js';
|
|
7
|
+
import { HandlerRegistry, } from './handler.js';
|
|
8
|
+
import { resolveRunnerId } from './identity.js';
|
|
9
|
+
import { consoleLogger } from './logger.js';
|
|
10
|
+
import { resolveOptions } from './options.js';
|
|
11
|
+
/**
|
|
12
|
+
* The Croniq runner: polls the server for work, dispatches handlers
|
|
13
|
+
* concurrently up to {@link CroniqRunnerOptions.maxInflight}, renews leases
|
|
14
|
+
* for in-flight executions, and reports completion.
|
|
15
|
+
*
|
|
16
|
+
* Call {@link run} to drive the loop yourself. Wire `SIGTERM`/`SIGINT` to
|
|
17
|
+
* the AbortController you pass in for graceful shutdown.
|
|
18
|
+
*/
|
|
19
|
+
export class CroniqRunner {
|
|
20
|
+
#options;
|
|
21
|
+
#client;
|
|
22
|
+
#registry = new HandlerRegistry();
|
|
23
|
+
#logger;
|
|
24
|
+
#instanceId = randomBytes(16).toString('hex');
|
|
25
|
+
#inflight = new Map();
|
|
26
|
+
#drainAC = new AbortController();
|
|
27
|
+
#runnerId;
|
|
28
|
+
#dispatcher;
|
|
29
|
+
#ran = false;
|
|
30
|
+
constructor(options) {
|
|
31
|
+
const defaultLogger = consoleLogger('warn', 'croniq');
|
|
32
|
+
this.#options = resolveOptions(options, defaultLogger);
|
|
33
|
+
this.#logger = this.#options.logger;
|
|
34
|
+
this.#client = new CroniqClient({
|
|
35
|
+
baseUrl: this.#options.serverUrl,
|
|
36
|
+
apiKey: this.#options.apiKey,
|
|
37
|
+
bearerToken: this.#options.bearerToken,
|
|
38
|
+
logger: this.#logger,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Register a handler for a specific `job_key`. If {@link JobRegistrationOptions.schedule}
|
|
43
|
+
* is set, the runner calls `POST /v1/jobs/register` for the job at startup
|
|
44
|
+
* (DSL precedence still applies server-side).
|
|
45
|
+
*/
|
|
46
|
+
handle(jobKey, handler, opts) {
|
|
47
|
+
this.#registry.register(jobKey, handler, opts);
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
/** Register a fallback handler for any job key that has no specific handler. */
|
|
51
|
+
setDefaultHandler(handler) {
|
|
52
|
+
this.#registry.registerDefault(handler);
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
/** The stable runner ID, available after {@link run} has started. */
|
|
56
|
+
get runnerId() {
|
|
57
|
+
if (!this.#runnerId)
|
|
58
|
+
throw new Error('runnerId is only available after run() starts');
|
|
59
|
+
return this.#runnerId;
|
|
60
|
+
}
|
|
61
|
+
/** Snapshot of currently in-flight execution IDs. Diagnostic only. */
|
|
62
|
+
get inflight() {
|
|
63
|
+
return [...this.#inflight.keys()];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Run the poll/dispatch/ack loop until {@link signal} aborts. Returns when
|
|
67
|
+
* the token signals AND all in-flight executions have either finished or
|
|
68
|
+
* the drain timeout elapses.
|
|
69
|
+
*/
|
|
70
|
+
async run(signal = new AbortController().signal) {
|
|
71
|
+
if (this.#ran)
|
|
72
|
+
throw new Error('CroniqRunner.run() may only be called once per instance');
|
|
73
|
+
this.#ran = true;
|
|
74
|
+
this.#runnerId = resolveRunnerId({
|
|
75
|
+
runnerId: this.#options.runnerId,
|
|
76
|
+
runnerIdPrefix: this.#options.runnerIdPrefix,
|
|
77
|
+
runnerDataDir: this.#options.runnerDataDir,
|
|
78
|
+
}, this.#logger);
|
|
79
|
+
this.#dispatcher = new ExecutionDispatcher({
|
|
80
|
+
client: this.#client,
|
|
81
|
+
registry: this.#registry,
|
|
82
|
+
options: this.#options,
|
|
83
|
+
runnerId: this.#runnerId,
|
|
84
|
+
runnerTags: this.#options.tags,
|
|
85
|
+
logger: this.#logger,
|
|
86
|
+
});
|
|
87
|
+
this.#logger.info('Croniq runner starting', {
|
|
88
|
+
runner_id: this.#runnerId,
|
|
89
|
+
capabilities: this.#options.capabilities.join(',') || '<none>',
|
|
90
|
+
max_inflight: this.#options.maxInflight,
|
|
91
|
+
});
|
|
92
|
+
await this.#selfRegisterSchedules(signal);
|
|
93
|
+
const loopSignal = anySignal(signal, this.#drainAC.signal);
|
|
94
|
+
// The runner's loop signal is observed by every poll, every sleep, and
|
|
95
|
+
// every in-flight dispatch — well above Node's default ceiling of 10
|
|
96
|
+
// abort listeners. Lift the cap rather than letting the runtime emit a
|
|
97
|
+
// misleading "memory leak" warning. (Each listener is cleaned up by its
|
|
98
|
+
// owner; the count just legitimately grows with `maxInflight`.)
|
|
99
|
+
setMaxListeners(0, loopSignal);
|
|
100
|
+
try {
|
|
101
|
+
await this.#pollLoop(loopSignal);
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
await this.#drain();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Signal graceful shutdown without waiting. Cancels new polls; in-flight
|
|
109
|
+
* handlers keep running until they complete or the drain-timeout elapses.
|
|
110
|
+
*/
|
|
111
|
+
requestDrain() {
|
|
112
|
+
if (!this.#drainAC.signal.aborted)
|
|
113
|
+
this.#drainAC.abort();
|
|
114
|
+
}
|
|
115
|
+
async #selfRegisterSchedules(signal) {
|
|
116
|
+
for (const entry of this.#registry.selfRegister) {
|
|
117
|
+
try {
|
|
118
|
+
const payload = {
|
|
119
|
+
job_key: entry.jobKey,
|
|
120
|
+
schedule: entry.schedule,
|
|
121
|
+
runner_id: this.#runnerId,
|
|
122
|
+
capabilities: this.#options.capabilities,
|
|
123
|
+
};
|
|
124
|
+
if (entry.timeout !== undefined)
|
|
125
|
+
payload.timeout = entry.timeout;
|
|
126
|
+
if (entry.description !== undefined)
|
|
127
|
+
payload.description = entry.description;
|
|
128
|
+
await this.#client.registerJob(payload, signal);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
this.#logger.warn(`self-register for job ${entry.jobKey} failed — runner will still poll, ` +
|
|
132
|
+
'but the server may not have a schedule', { job_key: entry.jobKey, error: String(err) });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async #pollLoop(signal) {
|
|
137
|
+
while (!signal.aborted) {
|
|
138
|
+
if (this.#inflight.size >= this.#options.maxInflight) {
|
|
139
|
+
try {
|
|
140
|
+
await sleep(this.#options.capacityBackoffMs, signal);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const request = {
|
|
148
|
+
runner_id: this.#runnerId,
|
|
149
|
+
capabilities: this.#options.capabilities,
|
|
150
|
+
max_inflight: this.#options.maxInflight,
|
|
151
|
+
inflight: [...this.#inflight.keys()],
|
|
152
|
+
instance_id: this.#instanceId,
|
|
153
|
+
tags: this.#options.tags,
|
|
154
|
+
};
|
|
155
|
+
let response;
|
|
156
|
+
try {
|
|
157
|
+
response = await this.#client.poll(request, this.#options.pollTimeoutMs, signal);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
if (signal.aborted)
|
|
161
|
+
return;
|
|
162
|
+
const detail = err instanceof HttpError
|
|
163
|
+
? { status: err.status, status_text: err.statusText }
|
|
164
|
+
: { error: String(err) };
|
|
165
|
+
this.#logger.warn(`poll failed — backing off ${this.#options.pollRetryDelayMs}ms`, detail);
|
|
166
|
+
try {
|
|
167
|
+
await sleep(this.#options.pollRetryDelayMs, signal);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
this.#handleCancellations(response.cancel);
|
|
175
|
+
for (const assignment of response.work) {
|
|
176
|
+
if (this.#inflight.has(assignment.execution_id))
|
|
177
|
+
continue;
|
|
178
|
+
const ac = new AbortController();
|
|
179
|
+
this.#inflight.set(assignment.execution_id, ac);
|
|
180
|
+
// Fire-and-forget; the inflight map cleans up in the .finally().
|
|
181
|
+
void this.#dispatcher
|
|
182
|
+
.dispatch(assignment, ac, signal)
|
|
183
|
+
.finally(() => {
|
|
184
|
+
this.#inflight.delete(assignment.execution_id);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
#handleCancellations(cancelIds) {
|
|
190
|
+
if (cancelIds.length === 0)
|
|
191
|
+
return;
|
|
192
|
+
for (const id of cancelIds) {
|
|
193
|
+
const ac = this.#inflight.get(id);
|
|
194
|
+
if (ac && !ac.signal.aborted) {
|
|
195
|
+
this.#logger.info(`server requested cancellation of execution ${id}`, { execution_id: id });
|
|
196
|
+
ac.abort();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async #drain() {
|
|
201
|
+
if (this.#inflight.size === 0)
|
|
202
|
+
return;
|
|
203
|
+
this.#logger.info(`draining ${this.#inflight.size} in-flight execution(s) (timeout ${this.#options.drainTimeoutMs}ms)`, { count: this.#inflight.size, timeout_ms: this.#options.drainTimeoutMs });
|
|
204
|
+
const deadline = Date.now() + this.#options.drainTimeoutMs;
|
|
205
|
+
while (this.#inflight.size > 0 && Date.now() < deadline) {
|
|
206
|
+
await sleep(50);
|
|
207
|
+
}
|
|
208
|
+
if (this.#inflight.size > 0) {
|
|
209
|
+
this.#logger.warn(`drain timed out with ${this.#inflight.size} execution(s) still in-flight — hard-cancelling`, { count: this.#inflight.size });
|
|
210
|
+
for (const ac of this.#inflight.values()) {
|
|
211
|
+
if (!ac.signal.aborted)
|
|
212
|
+
ac.abort();
|
|
213
|
+
}
|
|
214
|
+
// Give the dispatcher one tick to process the abort and ack.
|
|
215
|
+
const hardDeadline = Date.now() + 1_000;
|
|
216
|
+
while (this.#inflight.size > 0 && Date.now() < hardDeadline) {
|
|
217
|
+
await sleep(25);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/** Convenience factory. Equivalent to `new CroniqRunner(options)`. */
|
|
223
|
+
export function createRunner(options) {
|
|
224
|
+
return new CroniqRunner(options);
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/url.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strips trailing forward slashes from a string. Linear in the length of
|
|
3
|
+
* the suffix that's stripped.
|
|
4
|
+
*
|
|
5
|
+
* trimTrailingSlashes("http://x") === "http://x"
|
|
6
|
+
* trimTrailingSlashes("http://x/") === "http://x"
|
|
7
|
+
* trimTrailingSlashes("http://x///") === "http://x"
|
|
8
|
+
*/
|
|
9
|
+
export declare function trimTrailingSlashes(value: string): string;
|
|
10
|
+
//# sourceMappingURL=url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMzD"}
|
package/dist/url.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Small URL utilities. Kept regex-free on purpose: CodeQL's "polynomial
|
|
2
|
+
// regex" heuristic flags even linear patterns like `/\/+$/` when the
|
|
3
|
+
// input is library-controlled, and the loop equivalent is both clearer
|
|
4
|
+
// and immune to the warning.
|
|
5
|
+
/**
|
|
6
|
+
* Strips trailing forward slashes from a string. Linear in the length of
|
|
7
|
+
* the suffix that's stripped.
|
|
8
|
+
*
|
|
9
|
+
* trimTrailingSlashes("http://x") === "http://x"
|
|
10
|
+
* trimTrailingSlashes("http://x/") === "http://x"
|
|
11
|
+
* trimTrailingSlashes("http://x///") === "http://x"
|
|
12
|
+
*/
|
|
13
|
+
export function trimTrailingSlashes(value) {
|
|
14
|
+
let end = value.length;
|
|
15
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47 /* '/' */) {
|
|
16
|
+
end--;
|
|
17
|
+
}
|
|
18
|
+
return end === value.length ? value : value.slice(0, end);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=url.js.map
|
package/dist/url.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url.js","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,qEAAqE;AACrE,uEAAuE;AACvE,6BAA6B;AAE7B;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,OAAO,GAAG,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,CAAC;QAC7D,GAAG,EAAE,CAAC;IACR,CAAC;IACD,OAAO,GAAG,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5D,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nuetzliches/croniq-runner",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Croniq runner SDK for Node.js. Polls a Croniq server for work, dispatches handlers, streams logs back.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/",
|
|
16
|
+
"README.md",
|
|
17
|
+
"CHANGELOG.md",
|
|
18
|
+
"LICENSE-MIT",
|
|
19
|
+
"LICENSE-APACHE"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc -p tsconfig.build.json",
|
|
26
|
+
"clean": "rm -rf dist coverage",
|
|
27
|
+
"lint": "eslint src test",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"test:watch": "vitest",
|
|
30
|
+
"test:coverage": "vitest run --coverage",
|
|
31
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@opentelemetry/api": "^1.9.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^20.11.30",
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
39
|
+
"@typescript-eslint/parser": "^7.18.0",
|
|
40
|
+
"@vitest/coverage-v8": "^2.1.9",
|
|
41
|
+
"eslint": "^8.57.1",
|
|
42
|
+
"typescript": "^5.5.4",
|
|
43
|
+
"vitest": "^2.1.9"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"croniq",
|
|
47
|
+
"cron",
|
|
48
|
+
"scheduler",
|
|
49
|
+
"runner",
|
|
50
|
+
"sdk",
|
|
51
|
+
"jobs"
|
|
52
|
+
],
|
|
53
|
+
"homepage": "https://github.com/nuetzliches/croniq/tree/main/sdks/typescript",
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "git+https://github.com/nuetzliches/croniq.git",
|
|
57
|
+
"directory": "sdks/typescript"
|
|
58
|
+
},
|
|
59
|
+
"license": "(MIT OR Apache-2.0)",
|
|
60
|
+
"bugs": {
|
|
61
|
+
"url": "https://github.com/nuetzliches/croniq/issues"
|
|
62
|
+
}
|
|
63
|
+
}
|