@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
package/dist/routes/jobsAdmin.js
CHANGED
|
@@ -1,103 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __assign = (this && this.__assign) || function () {
|
|
3
|
-
__assign = Object.assign || function(t) {
|
|
4
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
-
s = arguments[i];
|
|
6
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
-
t[p] = s[p];
|
|
8
|
-
}
|
|
9
|
-
return t;
|
|
10
|
-
};
|
|
11
|
-
return __assign.apply(this, arguments);
|
|
12
|
-
};
|
|
13
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
-
});
|
|
21
|
-
};
|
|
22
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
-
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);
|
|
24
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
-
function step(op) {
|
|
27
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
-
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;
|
|
30
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
-
switch (op[0]) {
|
|
32
|
-
case 0: case 1: t = op; break;
|
|
33
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
-
default:
|
|
37
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
-
if (t[2]) _.ops.pop();
|
|
42
|
-
_.trys.pop(); continue;
|
|
43
|
-
}
|
|
44
|
-
op = body.call(thisArg, _);
|
|
45
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
50
|
-
var t = {};
|
|
51
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
52
|
-
t[p] = s[p];
|
|
53
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
54
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
55
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
56
|
-
t[p[i]] = s[p[i]];
|
|
57
|
-
}
|
|
58
|
-
return t;
|
|
59
|
-
};
|
|
60
|
-
var __values = (this && this.__values) || function(o) {
|
|
61
|
-
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
62
|
-
if (m) return m.call(o);
|
|
63
|
-
if (o && typeof o.length === "number") return {
|
|
64
|
-
next: function () {
|
|
65
|
-
if (o && i >= o.length) o = void 0;
|
|
66
|
-
return { value: o && o[i++], done: !o };
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
70
|
-
};
|
|
71
|
-
var __read = (this && this.__read) || function (o, n) {
|
|
72
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
73
|
-
if (!m) return o;
|
|
74
|
-
var i = m.call(o), r, ar = [], e;
|
|
75
|
-
try {
|
|
76
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
77
|
-
}
|
|
78
|
-
catch (error) { e = { error: error }; }
|
|
79
|
-
finally {
|
|
80
|
-
try {
|
|
81
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
82
|
-
}
|
|
83
|
-
finally { if (e) throw e.error; }
|
|
84
|
-
}
|
|
85
|
-
return ar;
|
|
86
|
-
};
|
|
87
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
88
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
89
4
|
};
|
|
90
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
91
6
|
exports.registerJobsAdminRoutes = void 0;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
7
|
+
const api_1 = require("@terreno/api");
|
|
8
|
+
const luxon_1 = require("luxon");
|
|
9
|
+
const mongoose_1 = __importDefault(require("mongoose"));
|
|
10
|
+
const job_1 = require("../models/job");
|
|
11
|
+
const jobSchedule_1 = require("../models/jobSchedule");
|
|
12
|
+
const DEFAULT_LIMIT = 50;
|
|
13
|
+
const MAX_LIMIT = 200;
|
|
14
|
+
const MAX_Q_LENGTH = 200;
|
|
15
|
+
const VALID_JOB_STATUSES = new Set([
|
|
101
16
|
"cancelled",
|
|
102
17
|
"completed",
|
|
103
18
|
"dead",
|
|
@@ -106,14 +21,14 @@ var VALID_JOB_STATUSES = new Set([
|
|
|
106
21
|
"running",
|
|
107
22
|
"scheduled",
|
|
108
23
|
]);
|
|
109
|
-
|
|
24
|
+
const JOB_ADMIN_ITEM_SCHEMA = {
|
|
110
25
|
_id: { type: "string" },
|
|
111
26
|
attemptCount: { type: "number" },
|
|
112
27
|
id: { type: "string" },
|
|
113
28
|
name: { type: "string" },
|
|
114
29
|
status: { type: "string" },
|
|
115
30
|
};
|
|
116
|
-
|
|
31
|
+
const SCHEDULE_ADMIN_ITEM_SCHEMA = {
|
|
117
32
|
cron: { type: "string" },
|
|
118
33
|
enabled: { type: "boolean" },
|
|
119
34
|
handlerName: { type: "string" },
|
|
@@ -122,21 +37,21 @@ var SCHEDULE_ADMIN_ITEM_SCHEMA = {
|
|
|
122
37
|
nextRunAt: { format: "date-time", type: "string" },
|
|
123
38
|
timezone: { type: "string" },
|
|
124
39
|
};
|
|
125
|
-
|
|
40
|
+
const pathParam = (value) => {
|
|
126
41
|
if (Array.isArray(value)) {
|
|
127
42
|
return value[0];
|
|
128
43
|
}
|
|
129
44
|
return value;
|
|
130
45
|
};
|
|
131
|
-
|
|
46
|
+
const readString = (value) => {
|
|
132
47
|
if (typeof value !== "string") {
|
|
133
48
|
return undefined;
|
|
134
49
|
}
|
|
135
|
-
|
|
50
|
+
const trimmed = value.trim();
|
|
136
51
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
137
52
|
};
|
|
138
|
-
|
|
139
|
-
|
|
53
|
+
const readPositiveInt = (value, fallback, max) => {
|
|
54
|
+
const parsed = typeof value === "number"
|
|
140
55
|
? value
|
|
141
56
|
: typeof value === "string" && value.trim().length > 0
|
|
142
57
|
? Number(value)
|
|
@@ -146,20 +61,20 @@ var readPositiveInt = function (value, fallback, max) {
|
|
|
146
61
|
}
|
|
147
62
|
return Math.min(Math.floor(parsed), max);
|
|
148
63
|
};
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
64
|
+
const escapeRegexLiteral = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
65
|
+
const parseIsoDate = (value, label) => {
|
|
66
|
+
const raw = readString(value);
|
|
152
67
|
if (!raw) {
|
|
153
68
|
return undefined;
|
|
154
69
|
}
|
|
155
|
-
|
|
70
|
+
const parsed = luxon_1.DateTime.fromISO(raw, { zone: "utc" });
|
|
156
71
|
if (!parsed.isValid) {
|
|
157
|
-
throw new api_1.APIError({ status: 400, title:
|
|
72
|
+
throw new api_1.APIError({ status: 400, title: `Invalid ${label}` });
|
|
158
73
|
}
|
|
159
74
|
return parsed.toJSDate();
|
|
160
75
|
};
|
|
161
|
-
|
|
162
|
-
|
|
76
|
+
const parseSearchQuery = (value) => {
|
|
77
|
+
const raw = readString(value);
|
|
163
78
|
if (!raw) {
|
|
164
79
|
return undefined;
|
|
165
80
|
}
|
|
@@ -168,8 +83,8 @@ var parseSearchQuery = function (value) {
|
|
|
168
83
|
}
|
|
169
84
|
return escapeRegexLiteral(raw);
|
|
170
85
|
};
|
|
171
|
-
|
|
172
|
-
|
|
86
|
+
const parseStatusFilter = (value) => {
|
|
87
|
+
const status = readString(value);
|
|
173
88
|
if (!status) {
|
|
174
89
|
return undefined;
|
|
175
90
|
}
|
|
@@ -178,15 +93,15 @@ var parseStatusFilter = function (value) {
|
|
|
178
93
|
}
|
|
179
94
|
return status;
|
|
180
95
|
};
|
|
181
|
-
|
|
96
|
+
const parseListFilters = (query) => ({
|
|
182
97
|
end: parseIsoDate(query.end, "end date"),
|
|
183
98
|
name: readString(query.name),
|
|
184
99
|
q: parseSearchQuery(query.q),
|
|
185
100
|
scheduleId: readString(query.scheduleId),
|
|
186
101
|
start: parseIsoDate(query.start, "start date"),
|
|
187
102
|
status: parseStatusFilter(query.status),
|
|
188
|
-
});
|
|
189
|
-
|
|
103
|
+
});
|
|
104
|
+
const EMPTY_STATUS_COUNTS = {
|
|
190
105
|
cancelled: 0,
|
|
191
106
|
completed: 0,
|
|
192
107
|
dead: 0,
|
|
@@ -195,31 +110,20 @@ var EMPTY_STATUS_COUNTS = {
|
|
|
195
110
|
running: 0,
|
|
196
111
|
scheduled: 0,
|
|
197
112
|
};
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
var row = grouped_1_1.value;
|
|
205
|
-
if (!VALID_JOB_STATUSES.has(row._id)) {
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
byStatus[row._id] = row.count;
|
|
209
|
-
total += row.count;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
213
|
-
finally {
|
|
214
|
-
try {
|
|
215
|
-
if (grouped_1_1 && !grouped_1_1.done && (_a = grouped_1.return)) _a.call(grouped_1);
|
|
113
|
+
const buildStatusCounts = (grouped) => {
|
|
114
|
+
const byStatus = { ...EMPTY_STATUS_COUNTS };
|
|
115
|
+
let total = 0;
|
|
116
|
+
for (const row of grouped) {
|
|
117
|
+
if (!VALID_JOB_STATUSES.has(row._id)) {
|
|
118
|
+
continue;
|
|
216
119
|
}
|
|
217
|
-
|
|
120
|
+
byStatus[row._id] = row.count;
|
|
121
|
+
total += row.count;
|
|
218
122
|
}
|
|
219
|
-
return { byStatus
|
|
123
|
+
return { byStatus, total };
|
|
220
124
|
};
|
|
221
|
-
|
|
222
|
-
|
|
125
|
+
const buildListMatch = (filters) => {
|
|
126
|
+
const match = {};
|
|
223
127
|
if (filters.name) {
|
|
224
128
|
match.name = filters.name;
|
|
225
129
|
}
|
|
@@ -233,7 +137,7 @@ var buildListMatch = function (filters) {
|
|
|
233
137
|
match.scheduleId = new mongoose_1.default.Types.ObjectId(filters.scheduleId);
|
|
234
138
|
}
|
|
235
139
|
if (filters.start || filters.end) {
|
|
236
|
-
|
|
140
|
+
const created = {};
|
|
237
141
|
if (filters.start) {
|
|
238
142
|
created.$gte = filters.start;
|
|
239
143
|
}
|
|
@@ -250,7 +154,7 @@ var buildListMatch = function (filters) {
|
|
|
250
154
|
}
|
|
251
155
|
return match;
|
|
252
156
|
};
|
|
253
|
-
|
|
157
|
+
const projectAdminPayload = (job, redactPayload) => {
|
|
254
158
|
if (job.payloadRedacted) {
|
|
255
159
|
return undefined;
|
|
256
160
|
}
|
|
@@ -263,70 +167,66 @@ var projectAdminPayload = function (job, redactPayload) {
|
|
|
263
167
|
payloadRedacted: job.payloadRedacted,
|
|
264
168
|
});
|
|
265
169
|
};
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
170
|
+
const serializeJob = (job, redactPayload) => {
|
|
171
|
+
const json = job.toJSON();
|
|
172
|
+
const { payload: _storedPayload, ...rest } = json;
|
|
173
|
+
const projectedPayload = projectAdminPayload(job, redactPayload);
|
|
270
174
|
if (projectedPayload === undefined) {
|
|
271
|
-
return
|
|
175
|
+
return {
|
|
176
|
+
...rest,
|
|
177
|
+
id: job._id.toString(),
|
|
178
|
+
};
|
|
272
179
|
}
|
|
273
|
-
return
|
|
180
|
+
return {
|
|
181
|
+
...rest,
|
|
182
|
+
id: job._id.toString(),
|
|
183
|
+
payload: projectedPayload,
|
|
184
|
+
};
|
|
274
185
|
};
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
return
|
|
186
|
+
const serializeSchedule = (schedule) => {
|
|
187
|
+
const json = schedule.toJSON();
|
|
188
|
+
return {
|
|
189
|
+
...json,
|
|
190
|
+
id: schedule._id.toString(),
|
|
191
|
+
};
|
|
278
192
|
};
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
if (!accessControl) return [3 /*break*/, 2];
|
|
290
|
-
return [4 /*yield*/, accessControl.can({
|
|
291
|
-
permissions: { admin: [api_1.ADMIN_PAGE_ACTION, "jobs"] },
|
|
292
|
-
user: user,
|
|
293
|
-
})];
|
|
294
|
-
case 1:
|
|
295
|
-
result = _a.sent();
|
|
296
|
-
if (!result.allowed) {
|
|
297
|
-
throw new api_1.ForbiddenError({
|
|
298
|
-
detail: result.reason,
|
|
299
|
-
title: "Jobs admin access required",
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
return [2 /*return*/];
|
|
303
|
-
case 2:
|
|
304
|
-
if (!user.admin) {
|
|
305
|
-
throw new api_1.ForbiddenError("Admin access required");
|
|
306
|
-
}
|
|
307
|
-
return [2 /*return*/];
|
|
308
|
-
}
|
|
193
|
+
const createRequireJobsAdmin = (accessControl) => async (req) => {
|
|
194
|
+
const user = req.user;
|
|
195
|
+
if (!user) {
|
|
196
|
+
throw new api_1.UnauthorizedError("Authentication required");
|
|
197
|
+
}
|
|
198
|
+
if (accessControl) {
|
|
199
|
+
const result = await accessControl.can({
|
|
200
|
+
permissions: { admin: [api_1.ADMIN_PAGE_ACTION, "jobs"] },
|
|
201
|
+
user: user,
|
|
309
202
|
});
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
.
|
|
320
|
-
|
|
321
|
-
.withQueryParameter("q", { type: "string" }, { required: false });
|
|
203
|
+
if (!result.allowed) {
|
|
204
|
+
throw new api_1.ForbiddenError({
|
|
205
|
+
detail: result.reason,
|
|
206
|
+
title: "Jobs admin access required",
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (!user.admin) {
|
|
212
|
+
throw new api_1.ForbiddenError("Admin access required");
|
|
213
|
+
}
|
|
322
214
|
};
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
215
|
+
const listQueryParameters = (builder) => builder
|
|
216
|
+
.withQueryParameter("page", { type: "number" }, { required: false })
|
|
217
|
+
.withQueryParameter("limit", { type: "number" }, { required: false })
|
|
218
|
+
.withQueryParameter("name", { type: "string" }, { required: false })
|
|
219
|
+
.withQueryParameter("status", { type: "string" }, { required: false })
|
|
220
|
+
.withQueryParameter("scheduleId", { type: "string" }, { required: false })
|
|
221
|
+
.withQueryParameter("start", { type: "string" }, { required: false })
|
|
222
|
+
.withQueryParameter("end", { type: "string" }, { required: false })
|
|
223
|
+
.withQueryParameter("q", { type: "string" }, { required: false });
|
|
224
|
+
const registerJobsAdminRoutes = ({ app, options, }) => {
|
|
225
|
+
const routeOpenApi = options.openApi ? { openApi: options.openApi } : {};
|
|
226
|
+
const requireJobsAdmin = createRequireJobsAdmin(options.accessControl);
|
|
227
|
+
const basePath = options.basePath;
|
|
228
|
+
const { jobsService, redactPayload } = options;
|
|
229
|
+
app.get(`${basePath}/schedules`, [
|
|
330
230
|
(0, api_1.authenticateMiddleware)(),
|
|
331
231
|
(0, api_1.createOpenApiBuilder)(routeOpenApi)
|
|
332
232
|
.withTags(["admin", "jobs"])
|
|
@@ -341,21 +241,12 @@ var registerJobsAdminRoutes = function (_a) {
|
|
|
341
241
|
},
|
|
342
242
|
})
|
|
343
243
|
.build(),
|
|
344
|
-
], (0, api_1.asyncHandler)(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
_a.sent();
|
|
351
|
-
return [4 /*yield*/, jobSchedule_1.JobSchedule.find({}).sort("name")];
|
|
352
|
-
case 2:
|
|
353
|
-
schedules = _a.sent();
|
|
354
|
-
return [2 /*return*/, res.json({ data: schedules.map(function (schedule) { return serializeSchedule(schedule); }) })];
|
|
355
|
-
}
|
|
356
|
-
});
|
|
357
|
-
}); }));
|
|
358
|
-
app.post("".concat(basePath, "/schedules/:name/pause"), [
|
|
244
|
+
], (0, api_1.asyncHandler)(async (req, res) => {
|
|
245
|
+
await requireJobsAdmin(req);
|
|
246
|
+
const schedules = await jobSchedule_1.JobSchedule.find({}).sort("name");
|
|
247
|
+
return res.json({ data: schedules.map((schedule) => serializeSchedule(schedule)) });
|
|
248
|
+
}));
|
|
249
|
+
app.post(`${basePath}/schedules/:name/pause`, [
|
|
359
250
|
(0, api_1.authenticateMiddleware)(),
|
|
360
251
|
(0, api_1.createOpenApiBuilder)(routeOpenApi)
|
|
361
252
|
.withTags(["admin", "jobs"])
|
|
@@ -363,25 +254,16 @@ var registerJobsAdminRoutes = function (_a) {
|
|
|
363
254
|
.withPathParameter("name", { type: "string" })
|
|
364
255
|
.withResponse(200, { data: { type: "object" } })
|
|
365
256
|
.build(),
|
|
366
|
-
], (0, api_1.asyncHandler)(
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
return [4 /*yield*/, jobsService.pauseSchedule(name)];
|
|
378
|
-
case 2:
|
|
379
|
-
schedule = _a.sent();
|
|
380
|
-
return [2 /*return*/, res.json({ data: serializeSchedule(schedule) })];
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
}); }));
|
|
384
|
-
app.post("".concat(basePath, "/schedules/:name/resume"), [
|
|
257
|
+
], (0, api_1.asyncHandler)(async (req, res) => {
|
|
258
|
+
await requireJobsAdmin(req);
|
|
259
|
+
const name = pathParam(req.params.name);
|
|
260
|
+
if (!name) {
|
|
261
|
+
throw new api_1.NotFoundError("Schedule not found");
|
|
262
|
+
}
|
|
263
|
+
const schedule = await jobsService.pauseSchedule(name);
|
|
264
|
+
return res.json({ data: serializeSchedule(schedule) });
|
|
265
|
+
}));
|
|
266
|
+
app.post(`${basePath}/schedules/:name/resume`, [
|
|
385
267
|
(0, api_1.authenticateMiddleware)(),
|
|
386
268
|
(0, api_1.createOpenApiBuilder)(routeOpenApi)
|
|
387
269
|
.withTags(["admin", "jobs"])
|
|
@@ -389,24 +271,15 @@ var registerJobsAdminRoutes = function (_a) {
|
|
|
389
271
|
.withPathParameter("name", { type: "string" })
|
|
390
272
|
.withResponse(200, { data: { type: "object" } })
|
|
391
273
|
.build(),
|
|
392
|
-
], (0, api_1.asyncHandler)(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
throw new api_1.NotFoundError("Schedule not found");
|
|
402
|
-
}
|
|
403
|
-
return [4 /*yield*/, jobsService.resumeSchedule(name)];
|
|
404
|
-
case 2:
|
|
405
|
-
schedule = _a.sent();
|
|
406
|
-
return [2 /*return*/, res.json({ data: serializeSchedule(schedule) })];
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
}); }));
|
|
274
|
+
], (0, api_1.asyncHandler)(async (req, res) => {
|
|
275
|
+
await requireJobsAdmin(req);
|
|
276
|
+
const name = pathParam(req.params.name);
|
|
277
|
+
if (!name) {
|
|
278
|
+
throw new api_1.NotFoundError("Schedule not found");
|
|
279
|
+
}
|
|
280
|
+
const schedule = await jobsService.resumeSchedule(name);
|
|
281
|
+
return res.json({ data: serializeSchedule(schedule) });
|
|
282
|
+
}));
|
|
410
283
|
app.get(basePath, [
|
|
411
284
|
(0, api_1.authenticateMiddleware)(),
|
|
412
285
|
listQueryParameters((0, api_1.createOpenApiBuilder)(routeOpenApi)
|
|
@@ -426,35 +299,26 @@ var registerJobsAdminRoutes = function (_a) {
|
|
|
426
299
|
total: { type: "number" },
|
|
427
300
|
})
|
|
428
301
|
.build(),
|
|
429
|
-
], (0, api_1.asyncHandler)(
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
_a = __read.apply(void 0, [_b.sent(), 2]), jobs = _a[0], total = _a[1];
|
|
447
|
-
return [2 /*return*/, res.json({
|
|
448
|
-
data: jobs.map(function (job) { return serializeJob(job, redactPayload); }),
|
|
449
|
-
limit: limit,
|
|
450
|
-
more: skip + limit < total,
|
|
451
|
-
page: page,
|
|
452
|
-
total: total,
|
|
453
|
-
})];
|
|
454
|
-
}
|
|
302
|
+
], (0, api_1.asyncHandler)(async (req, res) => {
|
|
303
|
+
await requireJobsAdmin(req);
|
|
304
|
+
const filters = parseListFilters(req.query);
|
|
305
|
+
const page = readPositiveInt(req.query.page, 1, Number.MAX_SAFE_INTEGER);
|
|
306
|
+
const limit = readPositiveInt(req.query.limit, DEFAULT_LIMIT, MAX_LIMIT);
|
|
307
|
+
const skip = (page - 1) * limit;
|
|
308
|
+
const match = buildListMatch(filters);
|
|
309
|
+
const [jobs, total] = await Promise.all([
|
|
310
|
+
job_1.Job.find(match).sort("-created").skip(skip).limit(limit),
|
|
311
|
+
job_1.Job.countDocuments(match),
|
|
312
|
+
]);
|
|
313
|
+
return res.json({
|
|
314
|
+
data: jobs.map((job) => serializeJob(job, redactPayload)),
|
|
315
|
+
limit,
|
|
316
|
+
more: skip + limit < total,
|
|
317
|
+
page,
|
|
318
|
+
total,
|
|
455
319
|
});
|
|
456
|
-
})
|
|
457
|
-
app.get(
|
|
320
|
+
}));
|
|
321
|
+
app.get(`${basePath}/stats`, [
|
|
458
322
|
(0, api_1.authenticateMiddleware)(),
|
|
459
323
|
(0, api_1.createOpenApiBuilder)(routeOpenApi)
|
|
460
324
|
.withTags(["admin", "jobs"])
|
|
@@ -469,23 +333,14 @@ var registerJobsAdminRoutes = function (_a) {
|
|
|
469
333
|
},
|
|
470
334
|
})
|
|
471
335
|
.build(),
|
|
472
|
-
], (0, api_1.asyncHandler)(
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
{ $group: { _id: "$status", count: { $sum: 1 } } },
|
|
481
|
-
])];
|
|
482
|
-
case 2:
|
|
483
|
-
grouped = _a.sent();
|
|
484
|
-
return [2 /*return*/, res.json({ data: buildStatusCounts(grouped) })];
|
|
485
|
-
}
|
|
486
|
-
});
|
|
487
|
-
}); }));
|
|
488
|
-
app.get("".concat(basePath, "/:id"), [
|
|
336
|
+
], (0, api_1.asyncHandler)(async (req, res) => {
|
|
337
|
+
await requireJobsAdmin(req);
|
|
338
|
+
const grouped = await job_1.Job.aggregate([
|
|
339
|
+
{ $group: { _id: "$status", count: { $sum: 1 } } },
|
|
340
|
+
]);
|
|
341
|
+
return res.json({ data: buildStatusCounts(grouped) });
|
|
342
|
+
}));
|
|
343
|
+
app.get(`${basePath}/:id`, [
|
|
489
344
|
(0, api_1.authenticateMiddleware)(),
|
|
490
345
|
(0, api_1.createOpenApiBuilder)(routeOpenApi)
|
|
491
346
|
.withTags(["admin", "jobs"])
|
|
@@ -493,28 +348,19 @@ var registerJobsAdminRoutes = function (_a) {
|
|
|
493
348
|
.withPathParameter("id", { type: "string" })
|
|
494
349
|
.withResponse(200, { data: { type: "object" } })
|
|
495
350
|
.build(),
|
|
496
|
-
], (0, api_1.asyncHandler)(
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
job = _a.sent();
|
|
510
|
-
if (!job) {
|
|
511
|
-
throw new api_1.NotFoundError("Job not found");
|
|
512
|
-
}
|
|
513
|
-
return [2 /*return*/, res.json({ data: serializeJob(job, redactPayload) })];
|
|
514
|
-
}
|
|
515
|
-
});
|
|
516
|
-
}); }));
|
|
517
|
-
app.post("".concat(basePath, "/:id/retry"), [
|
|
351
|
+
], (0, api_1.asyncHandler)(async (req, res) => {
|
|
352
|
+
await requireJobsAdmin(req);
|
|
353
|
+
const id = pathParam(req.params.id);
|
|
354
|
+
if (!id || !mongoose_1.default.isValidObjectId(id)) {
|
|
355
|
+
throw new api_1.NotFoundError("Job not found");
|
|
356
|
+
}
|
|
357
|
+
const job = await job_1.Job.findOneOrNone({ _id: id });
|
|
358
|
+
if (!job) {
|
|
359
|
+
throw new api_1.NotFoundError("Job not found");
|
|
360
|
+
}
|
|
361
|
+
return res.json({ data: serializeJob(job, redactPayload) });
|
|
362
|
+
}));
|
|
363
|
+
app.post(`${basePath}/:id/retry`, [
|
|
518
364
|
(0, api_1.authenticateMiddleware)(),
|
|
519
365
|
(0, api_1.createOpenApiBuilder)(routeOpenApi)
|
|
520
366
|
.withTags(["admin", "jobs"])
|
|
@@ -522,25 +368,16 @@ var registerJobsAdminRoutes = function (_a) {
|
|
|
522
368
|
.withPathParameter("id", { type: "string" })
|
|
523
369
|
.withResponse(200, { data: { type: "object" } })
|
|
524
370
|
.build(),
|
|
525
|
-
], (0, api_1.asyncHandler)(
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
536
|
-
return [4 /*yield*/, jobsService.adminRetryJob(id)];
|
|
537
|
-
case 2:
|
|
538
|
-
retry = (_a.sent()).retry;
|
|
539
|
-
return [2 /*return*/, res.json({ data: serializeJob(retry, redactPayload) })];
|
|
540
|
-
}
|
|
541
|
-
});
|
|
542
|
-
}); }));
|
|
543
|
-
app.post("".concat(basePath, "/:id/requeue"), [
|
|
371
|
+
], (0, api_1.asyncHandler)(async (req, res) => {
|
|
372
|
+
await requireJobsAdmin(req);
|
|
373
|
+
const id = pathParam(req.params.id);
|
|
374
|
+
if (!id || !mongoose_1.default.isValidObjectId(id)) {
|
|
375
|
+
throw new api_1.NotFoundError("Job not found");
|
|
376
|
+
}
|
|
377
|
+
const { retry } = await jobsService.adminRetryJob(id);
|
|
378
|
+
return res.json({ data: serializeJob(retry, redactPayload) });
|
|
379
|
+
}));
|
|
380
|
+
app.post(`${basePath}/:id/requeue`, [
|
|
544
381
|
(0, api_1.authenticateMiddleware)(),
|
|
545
382
|
(0, api_1.createOpenApiBuilder)(routeOpenApi)
|
|
546
383
|
.withTags(["admin", "jobs"])
|
|
@@ -548,25 +385,16 @@ var registerJobsAdminRoutes = function (_a) {
|
|
|
548
385
|
.withPathParameter("id", { type: "string" })
|
|
549
386
|
.withResponse(200, { data: { type: "object" } })
|
|
550
387
|
.build(),
|
|
551
|
-
], (0, api_1.asyncHandler)(
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
}
|
|
562
|
-
return [4 /*yield*/, jobsService.adminRequeueJob(id)];
|
|
563
|
-
case 2:
|
|
564
|
-
job = _a.sent();
|
|
565
|
-
return [2 /*return*/, res.json({ data: serializeJob(job, redactPayload) })];
|
|
566
|
-
}
|
|
567
|
-
});
|
|
568
|
-
}); }));
|
|
569
|
-
app.post("".concat(basePath, "/:id/cancel"), [
|
|
388
|
+
], (0, api_1.asyncHandler)(async (req, res) => {
|
|
389
|
+
await requireJobsAdmin(req);
|
|
390
|
+
const id = pathParam(req.params.id);
|
|
391
|
+
if (!id || !mongoose_1.default.isValidObjectId(id)) {
|
|
392
|
+
throw new api_1.NotFoundError("Job not found");
|
|
393
|
+
}
|
|
394
|
+
const job = await jobsService.adminRequeueJob(id);
|
|
395
|
+
return res.json({ data: serializeJob(job, redactPayload) });
|
|
396
|
+
}));
|
|
397
|
+
app.post(`${basePath}/:id/cancel`, [
|
|
570
398
|
(0, api_1.authenticateMiddleware)(),
|
|
571
399
|
(0, api_1.createOpenApiBuilder)(routeOpenApi)
|
|
572
400
|
.withTags(["admin", "jobs"])
|
|
@@ -574,23 +402,14 @@ var registerJobsAdminRoutes = function (_a) {
|
|
|
574
402
|
.withPathParameter("id", { type: "string" })
|
|
575
403
|
.withResponse(200, { data: { type: "object" } })
|
|
576
404
|
.build(),
|
|
577
|
-
], (0, api_1.asyncHandler)(
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
throw new api_1.NotFoundError("Job not found");
|
|
587
|
-
}
|
|
588
|
-
return [4 /*yield*/, jobsService.adminCancelJob(id)];
|
|
589
|
-
case 2:
|
|
590
|
-
job = _a.sent();
|
|
591
|
-
return [2 /*return*/, res.json({ data: serializeJob(job, redactPayload) })];
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
|
-
}); }));
|
|
405
|
+
], (0, api_1.asyncHandler)(async (req, res) => {
|
|
406
|
+
await requireJobsAdmin(req);
|
|
407
|
+
const id = pathParam(req.params.id);
|
|
408
|
+
if (!id || !mongoose_1.default.isValidObjectId(id)) {
|
|
409
|
+
throw new api_1.NotFoundError("Job not found");
|
|
410
|
+
}
|
|
411
|
+
const job = await jobsService.adminCancelJob(id);
|
|
412
|
+
return res.json({ data: serializeJob(job, redactPayload) });
|
|
413
|
+
}));
|
|
595
414
|
};
|
|
596
415
|
exports.registerJobsAdminRoutes = registerJobsAdminRoutes;
|