@cronwatch/sdk 0.7.0 → 0.8.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/anthropic.cjs +13 -2
- package/dist/anthropic.cjs.map +1 -1
- package/dist/anthropic.js +13 -2
- package/dist/anthropic.js.map +1 -1
- package/dist/bugsnag.cjs +8 -1
- package/dist/bugsnag.cjs.map +1 -1
- package/dist/bugsnag.js +8 -1
- package/dist/bugsnag.js.map +1 -1
- package/dist/d1.cjs +4 -1
- package/dist/d1.cjs.map +1 -1
- package/dist/d1.js +4 -1
- package/dist/d1.js.map +1 -1
- package/dist/datadog.cjs.map +1 -1
- package/dist/datadog.js.map +1 -1
- package/dist/discord.cjs.map +1 -1
- package/dist/discord.js.map +1 -1
- package/dist/honeybadger.cjs +8 -1
- package/dist/honeybadger.cjs.map +1 -1
- package/dist/honeybadger.js +8 -1
- package/dist/honeybadger.js.map +1 -1
- package/dist/index.cjs +69 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +69 -20
- package/dist/index.js.map +1 -1
- package/dist/mailgun.cjs.map +1 -1
- package/dist/mailgun.js.map +1 -1
- package/dist/newrelic.cjs.map +1 -1
- package/dist/newrelic.js.map +1 -1
- package/dist/pg-cron.cjs +8 -1
- package/dist/pg-cron.cjs.map +1 -1
- package/dist/pg-cron.js +8 -1
- package/dist/pg-cron.js.map +1 -1
- package/dist/postgres.cjs +6 -1
- package/dist/postgres.cjs.map +1 -1
- package/dist/postgres.js +6 -1
- package/dist/postgres.js.map +1 -1
- package/dist/postmark.cjs.map +1 -1
- package/dist/postmark.js.map +1 -1
- package/dist/resend.cjs.map +1 -1
- package/dist/resend.js.map +1 -1
- package/dist/rollbar.cjs +8 -1
- package/dist/rollbar.cjs.map +1 -1
- package/dist/rollbar.js +8 -1
- package/dist/rollbar.js.map +1 -1
- package/dist/sendgrid.cjs.map +1 -1
- package/dist/sendgrid.js.map +1 -1
- package/dist/sentry.cjs +8 -1
- package/dist/sentry.cjs.map +1 -1
- package/dist/sentry.js +8 -1
- package/dist/sentry.js.map +1 -1
- package/dist/ses.cjs.map +1 -1
- package/dist/ses.js.map +1 -1
- package/dist/slack.cjs.map +1 -1
- package/dist/slack.js.map +1 -1
- package/dist/sqlite.cjs +4 -1
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.js +4 -1
- package/dist/sqlite.js.map +1 -1
- package/dist/twilio.cjs.map +1 -1
- package/dist/twilio.js.map +1 -1
- package/dist/webhook.cjs.map +1 -1
- package/dist/webhook.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -65,6 +65,14 @@ function formatRelative(at, now) {
|
|
|
65
65
|
if (abs < 5e3) return text;
|
|
66
66
|
return diff < 0 ? `${text} ago` : `in ${text}`;
|
|
67
67
|
}
|
|
68
|
+
var FIRST_DATE_MS = -621355968e5;
|
|
69
|
+
var LAST_DATE_MS = 253402300799999;
|
|
70
|
+
function isoTime(at) {
|
|
71
|
+
return at >= FIRST_DATE_MS && at <= LAST_DATE_MS ? new Date(at).toISOString() : null;
|
|
72
|
+
}
|
|
73
|
+
function beyondDates(at) {
|
|
74
|
+
return at > LAST_DATE_MS ? "after 9999-12-31 23:59:59 UTC" : "before 0001-01-01 00:00:00 UTC";
|
|
75
|
+
}
|
|
68
76
|
|
|
69
77
|
// src/env.ts
|
|
70
78
|
function readEnv(name) {
|
|
@@ -102,15 +110,36 @@ function parseSchedule(schedule, timezone) {
|
|
|
102
110
|
cache.set(key, parsed);
|
|
103
111
|
return parsed;
|
|
104
112
|
}
|
|
113
|
+
var CYCLE_MS = 146097 * 864e5;
|
|
114
|
+
var CRONER_FIRST_MS = Date.UTC(400, 0, 1);
|
|
115
|
+
var CRONER_LAST_MS = Date.UTC(2800, 0, 1);
|
|
116
|
+
function runsAfter(cron, n, from) {
|
|
117
|
+
let shift = 0;
|
|
118
|
+
if (from < CRONER_FIRST_MS) shift = Math.ceil((CRONER_FIRST_MS - from) / CYCLE_MS) * CYCLE_MS;
|
|
119
|
+
else if (from >= CRONER_LAST_MS) shift = -(Math.floor((from - CRONER_LAST_MS) / CYCLE_MS) + 1) * CYCLE_MS;
|
|
120
|
+
const out = [];
|
|
121
|
+
for (const date of cron.nextRuns(n, new Date(from + shift))) {
|
|
122
|
+
const t = date.getTime() - shift;
|
|
123
|
+
if (t > LAST_DATE_MS) break;
|
|
124
|
+
out.push(t);
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
function countFrom(from) {
|
|
129
|
+
if (from >= LAST_DATE_MS) return null;
|
|
130
|
+
return from >= FIRST_DATE_MS ? from : FIRST_DATE_MS - 1;
|
|
131
|
+
}
|
|
105
132
|
function fireAfter(parsed, from) {
|
|
106
133
|
const cron = crons.get(parsed);
|
|
107
134
|
if (!cron) throw new Error(`schedule "${parsed.source}" was not made by parseSchedule`);
|
|
108
|
-
|
|
135
|
+
const start = countFrom(from);
|
|
136
|
+
if (start === null) return null;
|
|
137
|
+
let probe = start;
|
|
109
138
|
for (let attempt = 0; attempt < 4; attempt++) {
|
|
110
|
-
const runs = cron
|
|
139
|
+
const runs = runsAfter(cron, 8, probe);
|
|
111
140
|
if (runs.length === 0) return null;
|
|
112
|
-
const found = runs.find((
|
|
113
|
-
if (found) return found
|
|
141
|
+
const found = runs.find((t) => t > start);
|
|
142
|
+
if (found !== void 0) return found;
|
|
114
143
|
probe += 36e5;
|
|
115
144
|
}
|
|
116
145
|
return null;
|
|
@@ -119,20 +148,21 @@ function firesBetween(parsed, from, to, limit) {
|
|
|
119
148
|
const cron = crons.get(parsed);
|
|
120
149
|
if (!cron) throw new Error(`schedule "${parsed.source}" was not made by parseSchedule`);
|
|
121
150
|
const out = [];
|
|
122
|
-
|
|
123
|
-
|
|
151
|
+
const start = countFrom(from);
|
|
152
|
+
if (start === null) return out;
|
|
153
|
+
let probe = start;
|
|
154
|
+
let last = start;
|
|
124
155
|
for (let guard = 0; guard < 1e3; guard++) {
|
|
125
|
-
const batch = cron
|
|
156
|
+
const batch = runsAfter(cron, Math.min(limit + 1 - out.length, 24), probe);
|
|
126
157
|
if (batch.length === 0) return out;
|
|
127
|
-
for (const
|
|
128
|
-
const t = date.getTime();
|
|
158
|
+
for (const t of batch) {
|
|
129
159
|
if (t <= last) continue;
|
|
130
160
|
if (t > to) return out;
|
|
131
161
|
out.push(t);
|
|
132
162
|
last = t;
|
|
133
163
|
if (out.length > limit) return null;
|
|
134
164
|
}
|
|
135
|
-
const end = batch[batch.length - 1]
|
|
165
|
+
const end = batch[batch.length - 1];
|
|
136
166
|
probe = end > probe ? end : probe + 36e5;
|
|
137
167
|
}
|
|
138
168
|
return out;
|
|
@@ -168,6 +198,7 @@ function runCovers(startedAt, dueAt, followingAt = null) {
|
|
|
168
198
|
}
|
|
169
199
|
function inSpringForwardGap(parsed, startedAt, fireAt) {
|
|
170
200
|
const LOOKBACK = 3 * 36e5;
|
|
201
|
+
if (fireAt - LOOKBACK < FIRST_DATE_MS) return false;
|
|
171
202
|
const after2 = utcOffset(fireAt, parsed.timezone);
|
|
172
203
|
const before = utcOffset(fireAt - LOOKBACK, parsed.timezone);
|
|
173
204
|
const gap = after2 - before;
|
|
@@ -204,8 +235,10 @@ function utcOffset(at, timezone) {
|
|
|
204
235
|
for (const part of format.formatToParts(new Date(at))) {
|
|
205
236
|
if (part.type !== "literal") parts[part.type] = Number(part.value);
|
|
206
237
|
}
|
|
207
|
-
const wall =
|
|
208
|
-
|
|
238
|
+
const wall = /* @__PURE__ */ new Date(0);
|
|
239
|
+
wall.setUTCFullYear(parts.year, parts.month - 1, parts.day);
|
|
240
|
+
wall.setUTCHours(parts.hour, parts.minute, parts.second);
|
|
241
|
+
return wall.getTime() - Math.floor(at / 1e3) * 1e3;
|
|
209
242
|
}
|
|
210
243
|
|
|
211
244
|
// src/stats.ts
|
|
@@ -228,6 +261,15 @@ var DEFAULT_TIMEOUT_MS = 60 * 6e4;
|
|
|
228
261
|
var SLOW_FLOOR_MS = 1e4;
|
|
229
262
|
var BASELINE_MIN_RUNS = 5;
|
|
230
263
|
var BASELINE_WINDOW = 20;
|
|
264
|
+
var MAX_DURATION_MS = Number.MAX_SAFE_INTEGER;
|
|
265
|
+
function runDuration(startedAt, finishedAt) {
|
|
266
|
+
const ms = finishedAt - startedAt;
|
|
267
|
+
return ms > 0 ? Math.min(ms, MAX_DURATION_MS) : 0;
|
|
268
|
+
}
|
|
269
|
+
function stateVersion(state) {
|
|
270
|
+
const version = state?.version;
|
|
271
|
+
return typeof version === "number" && Number.isSafeInteger(version) && version >= 0 ? version + 0 : 0;
|
|
272
|
+
}
|
|
231
273
|
function emptyState(job) {
|
|
232
274
|
return { job, open: {}, consecutiveFailures: 0, silencedUntil: null, lastAlertAt: null, pendingRecovery: [], undelivered: [] };
|
|
233
275
|
}
|
|
@@ -438,7 +480,9 @@ function summary(stored, recent, state, nextExpectedAt, health) {
|
|
|
438
480
|
// src/format.ts
|
|
439
481
|
function when(at, now) {
|
|
440
482
|
if (at === null || at === void 0) return "never";
|
|
441
|
-
|
|
483
|
+
const iso = isoTime(at);
|
|
484
|
+
if (iso === null) return beyondDates(at);
|
|
485
|
+
return `${iso.replace("T", " ").slice(0, 19)} UTC (${formatRelative(at, now)})`;
|
|
442
486
|
}
|
|
443
487
|
function firstLines(text, n) {
|
|
444
488
|
if (!text) return "";
|
|
@@ -834,9 +878,13 @@ function dayLabel(t) {
|
|
|
834
878
|
return `${WEEKDAYS[d.getUTCDay()]} ${d.getUTCDate()} ${MONTHS[d.getUTCMonth()]}`;
|
|
835
879
|
}
|
|
836
880
|
function when2(t, now) {
|
|
881
|
+
if (t > LAST_DATE_MS) return "after 31 Dec 9999 23:59";
|
|
882
|
+
if (!(t >= FIRST_DATE_MS)) return "before 1 Jan 0001 00:00";
|
|
837
883
|
if (Math.floor(t / DAY) === Math.floor(now / DAY)) return clock(t);
|
|
838
884
|
const d = new Date(t);
|
|
839
|
-
|
|
885
|
+
const year = d.getUTCFullYear();
|
|
886
|
+
const other = year === new Date(now).getUTCFullYear() ? "" : ` ${String(year).padStart(4, "0")}`;
|
|
887
|
+
return `${d.getUTCDate()} ${MONTHS[d.getUTCMonth()]}${other} ${clock(t)}`;
|
|
840
888
|
}
|
|
841
889
|
function parsedSchedule(job) {
|
|
842
890
|
if (!job.definition.schedule) return null;
|
|
@@ -1327,7 +1375,8 @@ function sparkline(runs) {
|
|
|
1327
1375
|
}
|
|
1328
1376
|
function stamp(at, now) {
|
|
1329
1377
|
if (at === null) return `<span class="muted">never</span>`;
|
|
1330
|
-
const iso =
|
|
1378
|
+
const iso = isoTime(at);
|
|
1379
|
+
if (iso === null) return `<span class="nowrap">${beyondDates(at)}</span>`;
|
|
1331
1380
|
return `<time class="nowrap" datetime="${iso}" title="${iso.replace("T", " ").slice(0, 19)} UTC">${h(formatRelative(at, now))}</time>`;
|
|
1332
1381
|
}
|
|
1333
1382
|
function healthFigures(jobs) {
|
|
@@ -1860,7 +1909,7 @@ function memory() {
|
|
|
1860
1909
|
states.set(state.job, clone(state));
|
|
1861
1910
|
},
|
|
1862
1911
|
async compareAndSetState(state, expectedVersion) {
|
|
1863
|
-
if ((states.get(state.job)
|
|
1912
|
+
if (stateVersion(states.get(state.job)) !== expectedVersion) return false;
|
|
1864
1913
|
states.set(state.job, clone(state));
|
|
1865
1914
|
return true;
|
|
1866
1915
|
},
|
|
@@ -2130,7 +2179,7 @@ var CronWatch = class {
|
|
|
2130
2179
|
const current = await this.readState(job);
|
|
2131
2180
|
const { state, result } = await change(current);
|
|
2132
2181
|
if (sameState(state, current)) return { state: current, result };
|
|
2133
|
-
const version = current
|
|
2182
|
+
const version = stateVersion(current);
|
|
2134
2183
|
const next = { ...state, version: version + 1 };
|
|
2135
2184
|
if (await this.writeState(next, version)) return { state: next, result };
|
|
2136
2185
|
if (attempt >= STATE_ATTEMPTS) {
|
|
@@ -2190,7 +2239,7 @@ var CronWatch = class {
|
|
|
2190
2239
|
}
|
|
2191
2240
|
const finishedAt = this.now();
|
|
2192
2241
|
run.finishedAt = finishedAt;
|
|
2193
|
-
run.durationMs =
|
|
2242
|
+
run.durationMs = runDuration(startedAt, finishedAt);
|
|
2194
2243
|
run.metrics = recorder.metrics();
|
|
2195
2244
|
run.output = recorder.output() ?? (typeof result === "string" ? capOutput(result) : null);
|
|
2196
2245
|
this.conclude(definition, run, result, error, threw, recorder.expectText() ?? (typeof result === "string" ? result : null));
|
|
@@ -2424,7 +2473,7 @@ ${id}`;
|
|
|
2424
2473
|
...from,
|
|
2425
2474
|
status: "running",
|
|
2426
2475
|
finishedAt,
|
|
2427
|
-
durationMs:
|
|
2476
|
+
durationMs: runDuration(from.startedAt, finishedAt),
|
|
2428
2477
|
error: null,
|
|
2429
2478
|
output: joinOutput(from.output, added),
|
|
2430
2479
|
metrics: { ...from.metrics, ...recorder.metrics() }
|
|
@@ -2613,7 +2662,7 @@ ${id}`;
|
|
|
2613
2662
|
const timeout = timeoutMs(definition);
|
|
2614
2663
|
run.status = "timeout";
|
|
2615
2664
|
run.finishedAt = now;
|
|
2616
|
-
run.durationMs =
|
|
2665
|
+
run.durationMs = runDuration(run.startedAt, now);
|
|
2617
2666
|
run.error = `Still running after ${formatDuration(timeout)}; marked as timed out`;
|
|
2618
2667
|
if (!await this.writeRunIf(run, ["running"])) continue;
|
|
2619
2668
|
alerts.push(...await this.finishRun(definition, run, now));
|