@terreno/jobs 57.4.0 → 57.6.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/README.md +3 -3
- package/dist/activeJobExecution.js +7 -7
- package/dist/claimLock.js +12 -14
- package/dist/dispatchCompensation.js +29 -83
- package/dist/dispatchError.js +12 -28
- package/dist/jobExecutor.js +178 -297
- package/dist/jobsApp.js +124 -234
- package/dist/jobsService.js +261 -461
- package/dist/models/job.js +9 -9
- package/dist/models/jobSchedule.js +4 -4
- package/dist/retryBackoff.js +11 -14
- package/dist/routes/jobsAdmin.js +189 -370
- package/dist/routes/jobsExecute.js +41 -101
- package/dist/runners/gcpCloudTasks.js +116 -200
- package/dist/runners/mongoRunner.js +90 -184
- package/dist/runners/vercelQueues.js +105 -194
- package/dist/scheduleCron.js +18 -27
- package/dist/scheduler.js +68 -170
- package/package.json +4 -4
- package/src/models/job.ts +4 -4
- package/src/models/jobSchedule.ts +3 -2
- package/src/tests/packageExports.test.ts +19 -3
- package/tsconfig.json +6 -21
|
@@ -1,178 +1,109 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __extends = (this && this.__extends) || (function () {
|
|
3
|
-
var extendStatics = function (d, b) {
|
|
4
|
-
extendStatics = Object.setPrototypeOf ||
|
|
5
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
-
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
-
return extendStatics(d, b);
|
|
8
|
-
};
|
|
9
|
-
return function (d, b) {
|
|
10
|
-
if (typeof b !== "function" && b !== null)
|
|
11
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
-
extendStatics(d, b);
|
|
13
|
-
function __() { this.constructor = d; }
|
|
14
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
-
};
|
|
16
|
-
})();
|
|
17
|
-
var __assign = (this && this.__assign) || function () {
|
|
18
|
-
__assign = Object.assign || function(t) {
|
|
19
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
20
|
-
s = arguments[i];
|
|
21
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
22
|
-
t[p] = s[p];
|
|
23
|
-
}
|
|
24
|
-
return t;
|
|
25
|
-
};
|
|
26
|
-
return __assign.apply(this, arguments);
|
|
27
|
-
};
|
|
28
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
29
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
30
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
31
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
32
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
33
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
34
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
35
|
-
});
|
|
36
|
-
};
|
|
37
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
38
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
39
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
40
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
41
|
-
function step(op) {
|
|
42
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
43
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
44
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
45
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
46
|
-
switch (op[0]) {
|
|
47
|
-
case 0: case 1: t = op; break;
|
|
48
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
49
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
50
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
51
|
-
default:
|
|
52
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
53
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
54
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
55
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
56
|
-
if (t[2]) _.ops.pop();
|
|
57
|
-
_.trys.pop(); continue;
|
|
58
|
-
}
|
|
59
|
-
op = body.call(thisArg, _);
|
|
60
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
61
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
65
3
|
exports.createVercelQueuesConsumer = exports.VercelQueuesRunner = exports.applyVercelQueueExecutionOutcome = exports.resolveVercelQueueConsumerRetry = exports.buildVercelQueueSendOptions = exports.computeVercelQueueRetryAfterSeconds = exports.clampVercelQueueRetryAfterSeconds = exports.resolveVercelQueueSendRetentionSeconds = exports.computeVercelQueueDelaySeconds = exports.VercelQueueConsumerControl = exports.VercelQueueRunAtBeyondLimitError = exports.VERCEL_QUEUE_LOCKED_RETRY_SECONDS = exports.VERCEL_QUEUE_DEFAULT_VISIBILITY_TIMEOUT_SECONDS = exports.VERCEL_QUEUE_MAX_VISIBILITY_TIMEOUT_SECONDS = exports.VERCEL_QUEUE_MIN_VISIBILITY_TIMEOUT_SECONDS = exports.VERCEL_QUEUE_MIN_RETENTION_SECONDS = exports.VERCEL_QUEUE_DEFAULT_RETENTION_SECONDS = exports.VERCEL_QUEUE_MAX_DELAY_SECONDS = void 0;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
4
|
+
const node_module_1 = require("node:module");
|
|
5
|
+
const luxon_1 = require("luxon");
|
|
6
|
+
const jobExecutor_1 = require("../jobExecutor");
|
|
69
7
|
/** Vercel Queues maximum delay and retention window (7 days). */
|
|
70
|
-
exports.VERCEL_QUEUE_MAX_DELAY_SECONDS =
|
|
71
|
-
exports.VERCEL_QUEUE_DEFAULT_RETENTION_SECONDS =
|
|
8
|
+
exports.VERCEL_QUEUE_MAX_DELAY_SECONDS = 604_800;
|
|
9
|
+
exports.VERCEL_QUEUE_DEFAULT_RETENTION_SECONDS = 86_400;
|
|
72
10
|
exports.VERCEL_QUEUE_MIN_RETENTION_SECONDS = 60;
|
|
73
11
|
exports.VERCEL_QUEUE_MIN_VISIBILITY_TIMEOUT_SECONDS = 30;
|
|
74
|
-
exports.VERCEL_QUEUE_MAX_VISIBILITY_TIMEOUT_SECONDS =
|
|
75
|
-
exports.VERCEL_QUEUE_DEFAULT_VISIBILITY_TIMEOUT_SECONDS =
|
|
12
|
+
exports.VERCEL_QUEUE_MAX_VISIBILITY_TIMEOUT_SECONDS = 3_600;
|
|
13
|
+
exports.VERCEL_QUEUE_DEFAULT_VISIBILITY_TIMEOUT_SECONDS = 1_800;
|
|
76
14
|
exports.VERCEL_QUEUE_LOCKED_RETRY_SECONDS = 30;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
}(Error));
|
|
15
|
+
const nodeRequire = (0, node_module_1.createRequire)(__filename);
|
|
16
|
+
class VercelQueueRunAtBeyondLimitError extends Error {
|
|
17
|
+
maxDelaySeconds;
|
|
18
|
+
runAt;
|
|
19
|
+
constructor(runAt, maxDelaySeconds) {
|
|
20
|
+
super(`Job runAt ${runAt.toISOString()} exceeds Vercel Queue maximum delay of ${maxDelaySeconds} seconds`);
|
|
21
|
+
this.name = "VercelQueueRunAtBeyondLimitError";
|
|
22
|
+
this.runAt = runAt;
|
|
23
|
+
this.maxDelaySeconds = maxDelaySeconds;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
89
26
|
exports.VercelQueueRunAtBeyondLimitError = VercelQueueRunAtBeyondLimitError;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return VercelQueueConsumerControl;
|
|
99
|
-
}(Error));
|
|
27
|
+
class VercelQueueConsumerControl extends Error {
|
|
28
|
+
directive;
|
|
29
|
+
constructor(directive) {
|
|
30
|
+
super("Vercel queue consumer control");
|
|
31
|
+
this.name = "VercelQueueConsumerControl";
|
|
32
|
+
this.directive = directive;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
100
35
|
exports.VercelQueueConsumerControl = VercelQueueConsumerControl;
|
|
101
|
-
|
|
102
|
-
|
|
36
|
+
const requireNonEmpty = (value, label) => {
|
|
37
|
+
const trimmed = value?.trim();
|
|
103
38
|
if (!trimmed) {
|
|
104
|
-
throw new Error(
|
|
39
|
+
throw new Error(`VercelQueuesRunner requires ${label}`);
|
|
105
40
|
}
|
|
106
41
|
return trimmed;
|
|
107
42
|
};
|
|
108
|
-
|
|
43
|
+
const validateRetentionSeconds = (retentionSeconds) => {
|
|
109
44
|
if (retentionSeconds === undefined) {
|
|
110
45
|
return undefined;
|
|
111
46
|
}
|
|
112
47
|
if (!Number.isFinite(retentionSeconds) ||
|
|
113
48
|
retentionSeconds < exports.VERCEL_QUEUE_MIN_RETENTION_SECONDS ||
|
|
114
49
|
retentionSeconds > exports.VERCEL_QUEUE_MAX_DELAY_SECONDS) {
|
|
115
|
-
throw new Error(
|
|
50
|
+
throw new Error(`VercelQueuesRunner retentionSeconds must be between ${exports.VERCEL_QUEUE_MIN_RETENTION_SECONDS} and ${exports.VERCEL_QUEUE_MAX_DELAY_SECONDS} seconds`);
|
|
116
51
|
}
|
|
117
52
|
return retentionSeconds;
|
|
118
53
|
};
|
|
119
|
-
|
|
54
|
+
const validateVisibilityTimeoutSeconds = (visibilityTimeoutSeconds) => {
|
|
120
55
|
if (visibilityTimeoutSeconds === undefined) {
|
|
121
56
|
return exports.VERCEL_QUEUE_DEFAULT_VISIBILITY_TIMEOUT_SECONDS;
|
|
122
57
|
}
|
|
123
58
|
if (!Number.isFinite(visibilityTimeoutSeconds) ||
|
|
124
59
|
visibilityTimeoutSeconds < exports.VERCEL_QUEUE_MIN_VISIBILITY_TIMEOUT_SECONDS ||
|
|
125
60
|
visibilityTimeoutSeconds > exports.VERCEL_QUEUE_MAX_VISIBILITY_TIMEOUT_SECONDS) {
|
|
126
|
-
throw new Error(
|
|
61
|
+
throw new Error(`VercelQueuesConsumer visibilityTimeoutSeconds must be between ${exports.VERCEL_QUEUE_MIN_VISIBILITY_TIMEOUT_SECONDS} and ${exports.VERCEL_QUEUE_MAX_VISIBILITY_TIMEOUT_SECONDS} seconds`);
|
|
127
62
|
}
|
|
128
63
|
return visibilityTimeoutSeconds;
|
|
129
64
|
};
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
});
|
|
137
|
-
};
|
|
138
|
-
var loadQueueSend = function () {
|
|
65
|
+
const resolveConfig = (config) => ({
|
|
66
|
+
region: config.region?.trim() || undefined,
|
|
67
|
+
retentionSeconds: validateRetentionSeconds(config.retentionSeconds),
|
|
68
|
+
topic: requireNonEmpty(config.topic, "topic"),
|
|
69
|
+
});
|
|
70
|
+
const loadQueueSend = () => {
|
|
139
71
|
try {
|
|
140
|
-
|
|
141
|
-
return
|
|
72
|
+
const module = nodeRequire("@vercel/queue");
|
|
73
|
+
return module.send;
|
|
142
74
|
}
|
|
143
|
-
catch
|
|
75
|
+
catch {
|
|
144
76
|
throw new Error("VercelQueuesRunner requires optional peer dependency @vercel/queue. " +
|
|
145
77
|
"Install it with: bun add @vercel/queue");
|
|
146
78
|
}
|
|
147
79
|
};
|
|
148
|
-
|
|
80
|
+
const loadHandleCallback = () => {
|
|
149
81
|
try {
|
|
150
|
-
|
|
151
|
-
return
|
|
82
|
+
const module = nodeRequire("@vercel/queue");
|
|
83
|
+
return module.handleCallback;
|
|
152
84
|
}
|
|
153
|
-
catch
|
|
85
|
+
catch {
|
|
154
86
|
throw new Error("createVercelQueuesConsumer requires optional peer dependency @vercel/queue. " +
|
|
155
87
|
"Install it with: bun add @vercel/queue");
|
|
156
88
|
}
|
|
157
89
|
};
|
|
158
|
-
|
|
90
|
+
const readJobId = (message) => {
|
|
159
91
|
if (!message || typeof message !== "object" || !("jobId" in message)) {
|
|
160
92
|
return undefined;
|
|
161
93
|
}
|
|
162
|
-
|
|
94
|
+
const { jobId } = message;
|
|
163
95
|
if (typeof jobId !== "string") {
|
|
164
96
|
return undefined;
|
|
165
97
|
}
|
|
166
|
-
|
|
98
|
+
const trimmed = jobId.trim();
|
|
167
99
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
168
100
|
};
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
var scheduled = luxon_1.DateTime.fromJSDate(runAt, { zone: "utc" });
|
|
101
|
+
const computeVercelQueueDelaySeconds = (runAt, now = luxon_1.DateTime.utc()) => {
|
|
102
|
+
const scheduled = luxon_1.DateTime.fromJSDate(runAt, { zone: "utc" });
|
|
172
103
|
if (scheduled <= now) {
|
|
173
104
|
return undefined;
|
|
174
105
|
}
|
|
175
|
-
|
|
106
|
+
const delaySeconds = Math.floor(scheduled.diff(now, "seconds").seconds);
|
|
176
107
|
if (delaySeconds <= 0) {
|
|
177
108
|
return undefined;
|
|
178
109
|
}
|
|
@@ -182,8 +113,8 @@ var computeVercelQueueDelaySeconds = function (runAt, now) {
|
|
|
182
113
|
return delaySeconds;
|
|
183
114
|
};
|
|
184
115
|
exports.computeVercelQueueDelaySeconds = computeVercelQueueDelaySeconds;
|
|
185
|
-
|
|
186
|
-
|
|
116
|
+
const resolveVercelQueueSendRetentionSeconds = (delaySeconds, configuredRetention) => {
|
|
117
|
+
const baseRetention = configuredRetention ?? exports.VERCEL_QUEUE_DEFAULT_RETENTION_SECONDS;
|
|
187
118
|
if (delaySeconds === undefined) {
|
|
188
119
|
return baseRetention;
|
|
189
120
|
}
|
|
@@ -191,44 +122,45 @@ var resolveVercelQueueSendRetentionSeconds = function (delaySeconds, configuredR
|
|
|
191
122
|
};
|
|
192
123
|
exports.resolveVercelQueueSendRetentionSeconds = resolveVercelQueueSendRetentionSeconds;
|
|
193
124
|
/** Clamp queue retry visibility changes to the vendor 0.5.1 range (30s–1h). */
|
|
194
|
-
|
|
195
|
-
return Math.max(exports.VERCEL_QUEUE_MIN_VISIBILITY_TIMEOUT_SECONDS, Math.min(seconds, exports.VERCEL_QUEUE_MAX_VISIBILITY_TIMEOUT_SECONDS));
|
|
196
|
-
};
|
|
125
|
+
const clampVercelQueueRetryAfterSeconds = (seconds) => Math.max(exports.VERCEL_QUEUE_MIN_VISIBILITY_TIMEOUT_SECONDS, Math.min(seconds, exports.VERCEL_QUEUE_MAX_VISIBILITY_TIMEOUT_SECONDS));
|
|
197
126
|
exports.clampVercelQueueRetryAfterSeconds = clampVercelQueueRetryAfterSeconds;
|
|
198
127
|
/**
|
|
199
128
|
* Seconds until {@link runAt}, clamped for `handleCallback` retry visibility (30–3600).
|
|
200
129
|
* not_due jobs more than 1h away retry at 3600s until due.
|
|
201
130
|
*/
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
var seconds = Math.ceil(luxon_1.DateTime.fromJSDate(runAt, { zone: "utc" }).diff(now, "seconds").seconds);
|
|
131
|
+
const computeVercelQueueRetryAfterSeconds = (runAt, now = luxon_1.DateTime.utc()) => {
|
|
132
|
+
const seconds = Math.ceil(luxon_1.DateTime.fromJSDate(runAt, { zone: "utc" }).diff(now, "seconds").seconds);
|
|
205
133
|
if (seconds <= 0) {
|
|
206
134
|
return exports.VERCEL_QUEUE_MIN_VISIBILITY_TIMEOUT_SECONDS;
|
|
207
135
|
}
|
|
208
136
|
return (0, exports.clampVercelQueueRetryAfterSeconds)(seconds);
|
|
209
137
|
};
|
|
210
138
|
exports.computeVercelQueueRetryAfterSeconds = computeVercelQueueRetryAfterSeconds;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
139
|
+
const buildVercelQueueSendOptions = (job, config, now = luxon_1.DateTime.utc()) => {
|
|
140
|
+
const delaySeconds = (0, exports.computeVercelQueueDelaySeconds)(job.runAt, now);
|
|
141
|
+
const retentionSeconds = (0, exports.resolveVercelQueueSendRetentionSeconds)(delaySeconds, config.retentionSeconds);
|
|
142
|
+
return {
|
|
143
|
+
idempotencyKey: job._id.toString(),
|
|
144
|
+
retentionSeconds,
|
|
145
|
+
...(config.region ? { region: config.region } : {}),
|
|
146
|
+
...(delaySeconds !== undefined ? { delaySeconds } : {}),
|
|
147
|
+
};
|
|
216
148
|
};
|
|
217
149
|
exports.buildVercelQueueSendOptions = buildVercelQueueSendOptions;
|
|
218
|
-
|
|
150
|
+
const normalizeRetryDirective = (directive) => {
|
|
219
151
|
if ("acknowledge" in directive) {
|
|
220
152
|
return directive;
|
|
221
153
|
}
|
|
222
154
|
return { afterSeconds: (0, exports.clampVercelQueueRetryAfterSeconds)(directive.afterSeconds) };
|
|
223
155
|
};
|
|
224
|
-
|
|
156
|
+
const resolveVercelQueueConsumerRetry = (error) => {
|
|
225
157
|
if (error instanceof VercelQueueConsumerControl) {
|
|
226
158
|
return normalizeRetryDirective(error.directive);
|
|
227
159
|
}
|
|
228
160
|
return undefined;
|
|
229
161
|
};
|
|
230
162
|
exports.resolveVercelQueueConsumerRetry = resolveVercelQueueConsumerRetry;
|
|
231
|
-
|
|
163
|
+
const applyVercelQueueExecutionOutcome = (outcome) => {
|
|
232
164
|
if (outcome.kind === "not_found") {
|
|
233
165
|
throw new VercelQueueConsumerControl({ acknowledge: true });
|
|
234
166
|
}
|
|
@@ -244,11 +176,11 @@ var applyVercelQueueExecutionOutcome = function (outcome) {
|
|
|
244
176
|
throw new VercelQueueConsumerControl({ afterSeconds: exports.VERCEL_QUEUE_LOCKED_RETRY_SECONDS });
|
|
245
177
|
}
|
|
246
178
|
if (outcome.job.status === "pending") {
|
|
247
|
-
|
|
248
|
-
|
|
179
|
+
const now = luxon_1.DateTime.utc();
|
|
180
|
+
const afterSeconds = outcome.job.runAt > now.toJSDate()
|
|
249
181
|
? (0, exports.computeVercelQueueRetryAfterSeconds)(outcome.job.runAt, now)
|
|
250
182
|
: exports.VERCEL_QUEUE_MIN_VISIBILITY_TIMEOUT_SECONDS;
|
|
251
|
-
throw new VercelQueueConsumerControl({ afterSeconds
|
|
183
|
+
throw new VercelQueueConsumerControl({ afterSeconds });
|
|
252
184
|
}
|
|
253
185
|
};
|
|
254
186
|
exports.applyVercelQueueExecutionOutcome = applyVercelQueueExecutionOutcome;
|
|
@@ -258,69 +190,48 @@ exports.applyVercelQueueExecutionOutcome = applyVercelQueueExecutionOutcome;
|
|
|
258
190
|
* Required `vercel.json` consumer (private route — platform auth only):
|
|
259
191
|
* `"experimentalTriggers": [{ "type": "queue/v2beta", "topic": "<topic>" }]`
|
|
260
192
|
*/
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
193
|
+
class VercelQueuesRunner {
|
|
194
|
+
id = "vercel-queues";
|
|
195
|
+
/**
|
|
196
|
+
* Vercel push consumers are private `handleCallback` routes, not Express
|
|
197
|
+
* `POST /jobs/execute`. Use {@link createVercelQueuesConsumer} on the consumer route.
|
|
198
|
+
*/
|
|
199
|
+
requiresExecuteRoute = false;
|
|
200
|
+
config;
|
|
201
|
+
send;
|
|
202
|
+
constructor(config) {
|
|
270
203
|
this.config = resolveConfig(config);
|
|
271
|
-
this.send =
|
|
204
|
+
this.send = config.send ?? loadQueueSend();
|
|
272
205
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
payload = { jobId: job._id.toString() };
|
|
280
|
-
options = (0, exports.buildVercelQueueSendOptions)(job, this.config);
|
|
281
|
-
return [4 /*yield*/, this.send(this.config.topic, payload, options)];
|
|
282
|
-
case 1:
|
|
283
|
-
_a.sent();
|
|
284
|
-
return [2 /*return*/];
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
});
|
|
288
|
-
};
|
|
289
|
-
return VercelQueuesRunner;
|
|
290
|
-
}());
|
|
206
|
+
async enqueue(job) {
|
|
207
|
+
const payload = { jobId: job._id.toString() };
|
|
208
|
+
const options = (0, exports.buildVercelQueueSendOptions)(job, this.config);
|
|
209
|
+
await this.send(this.config.topic, payload, options);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
291
212
|
exports.VercelQueuesRunner = VercelQueuesRunner;
|
|
292
213
|
/**
|
|
293
214
|
* Wraps vendor `handleCallback` to execute a queued `{jobId}` through Terreno's
|
|
294
215
|
* Mongo-backed {@link executeJobById} seam. Platform auth stays in the vendor handler.
|
|
295
216
|
*/
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
return [4 /*yield*/, (0, jobExecutor_1.executeJobById)({
|
|
311
|
-
host: options.host,
|
|
312
|
-
jobId: jobId,
|
|
313
|
-
signal: signal,
|
|
314
|
-
})];
|
|
315
|
-
case 1:
|
|
316
|
-
outcome = _a.sent();
|
|
317
|
-
(0, exports.applyVercelQueueExecutionOutcome)(outcome);
|
|
318
|
-
return [2 /*return*/];
|
|
319
|
-
}
|
|
217
|
+
const createVercelQueuesConsumer = (options) => {
|
|
218
|
+
const handleCallback = options.handleCallback ?? loadHandleCallback();
|
|
219
|
+
const signal = options.signal ?? AbortSignal.timeout(30 * 60 * 1_000);
|
|
220
|
+
const visibilityTimeoutSeconds = validateVisibilityTimeoutSeconds(options.visibilityTimeoutSeconds);
|
|
221
|
+
return handleCallback(async (message) => {
|
|
222
|
+
const jobId = readJobId(message);
|
|
223
|
+
if (!jobId) {
|
|
224
|
+
throw new VercelQueueConsumerControl({ acknowledge: true });
|
|
225
|
+
}
|
|
226
|
+
const outcome = await (0, jobExecutor_1.executeJobById)({
|
|
227
|
+
host: options.host,
|
|
228
|
+
jobId,
|
|
229
|
+
signal,
|
|
320
230
|
});
|
|
321
|
-
|
|
231
|
+
(0, exports.applyVercelQueueExecutionOutcome)(outcome);
|
|
232
|
+
}, {
|
|
322
233
|
retry: exports.resolveVercelQueueConsumerRetry,
|
|
323
|
-
visibilityTimeoutSeconds
|
|
234
|
+
visibilityTimeoutSeconds,
|
|
324
235
|
});
|
|
325
236
|
};
|
|
326
237
|
exports.createVercelQueuesConsumer = createVercelQueuesConsumer;
|
package/dist/scheduleCron.js
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.computeNextRunAtAfter = exports.computeInitialNextRunAt = exports.validateScheduleDefinition = exports.assertValidCronExpression = exports.assertValidIanaTimezone = exports.resolveScheduleTimezone = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
var defaultTimezone = _a.defaultTimezone, scheduleTimezone = _a.scheduleTimezone;
|
|
11
|
-
return scheduleTimezone !== null && scheduleTimezone !== void 0 ? scheduleTimezone : defaultTimezone;
|
|
12
|
-
};
|
|
4
|
+
const api_1 = require("@terreno/api");
|
|
5
|
+
const cron_1 = require("cron");
|
|
6
|
+
const luxon_1 = require("luxon");
|
|
7
|
+
const INVALID_CRON_TITLE = "Invalid cron expression";
|
|
8
|
+
const INVALID_TIMEZONE_TITLE = "Invalid IANA timezone";
|
|
9
|
+
const resolveScheduleTimezone = ({ defaultTimezone, scheduleTimezone, }) => scheduleTimezone ?? defaultTimezone;
|
|
13
10
|
exports.resolveScheduleTimezone = resolveScheduleTimezone;
|
|
14
11
|
/** @internal */
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
var zoneCheck = luxon_1.DateTime.now().setZone(timezone);
|
|
12
|
+
const assertValidIanaTimezone = (timezone) => {
|
|
13
|
+
const zoneCheck = luxon_1.DateTime.now().setZone(timezone);
|
|
18
14
|
if (!zoneCheck.isValid) {
|
|
19
15
|
throw new api_1.APIError({
|
|
20
|
-
detail:
|
|
16
|
+
detail: zoneCheck.invalidReason ?? "Timezone is not a valid IANA identifier",
|
|
21
17
|
status: 400,
|
|
22
18
|
title: INVALID_TIMEZONE_TITLE,
|
|
23
19
|
});
|
|
@@ -25,37 +21,32 @@ var assertValidIanaTimezone = function (timezone) {
|
|
|
25
21
|
};
|
|
26
22
|
exports.assertValidIanaTimezone = assertValidIanaTimezone;
|
|
27
23
|
/** @internal */
|
|
28
|
-
|
|
24
|
+
const assertValidCronExpression = (cron, timezone) => {
|
|
29
25
|
try {
|
|
30
26
|
new cron_1.CronTime(cron, timezone);
|
|
31
27
|
}
|
|
32
28
|
catch (error) {
|
|
33
|
-
|
|
29
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
34
30
|
throw new api_1.APIError({
|
|
35
31
|
cause: error instanceof Error ? error : undefined,
|
|
36
|
-
detail
|
|
32
|
+
detail,
|
|
37
33
|
status: 400,
|
|
38
34
|
title: INVALID_CRON_TITLE,
|
|
39
35
|
});
|
|
40
36
|
}
|
|
41
37
|
};
|
|
42
38
|
exports.assertValidCronExpression = assertValidCronExpression;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
scheduleTimezone: scheduleTimezone,
|
|
39
|
+
const validateScheduleDefinition = ({ cron, defaultTimezone, scheduleTimezone, }) => {
|
|
40
|
+
const timezone = (0, exports.resolveScheduleTimezone)({
|
|
41
|
+
defaultTimezone,
|
|
42
|
+
scheduleTimezone,
|
|
48
43
|
});
|
|
49
44
|
(0, exports.assertValidIanaTimezone)(timezone);
|
|
50
45
|
(0, exports.assertValidCronExpression)(cron, timezone);
|
|
51
46
|
return timezone;
|
|
52
47
|
};
|
|
53
48
|
exports.validateScheduleDefinition = validateScheduleDefinition;
|
|
54
|
-
|
|
55
|
-
return (0, exports.computeNextRunAtAfter)(cron, timezone, luxon_1.DateTime.utc().toJSDate());
|
|
56
|
-
};
|
|
49
|
+
const computeInitialNextRunAt = (cron, timezone) => (0, exports.computeNextRunAtAfter)(cron, timezone, luxon_1.DateTime.utc().toJSDate());
|
|
57
50
|
exports.computeInitialNextRunAt = computeInitialNextRunAt;
|
|
58
|
-
|
|
59
|
-
return new cron_1.CronTime(cron, timezone).getNextDateFrom(after, timezone).toJSDate();
|
|
60
|
-
};
|
|
51
|
+
const computeNextRunAtAfter = (cron, timezone, after) => new cron_1.CronTime(cron, timezone).getNextDateFrom(after, timezone).toJSDate();
|
|
61
52
|
exports.computeNextRunAtAfter = computeNextRunAtAfter;
|