velocious 1.0.176 → 1.0.178
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 +89 -0
- package/build/src/background-jobs/client.d.ts +23 -0
- package/build/src/background-jobs/client.d.ts.map +1 -0
- package/build/src/background-jobs/client.js +58 -0
- package/build/src/background-jobs/job-record.d.ts +4 -0
- package/build/src/background-jobs/job-record.d.ts.map +1 -0
- package/build/src/background-jobs/job-record.js +11 -0
- package/build/src/background-jobs/job-registry.d.ts +23 -0
- package/build/src/background-jobs/job-registry.d.ts.map +1 -0
- package/build/src/background-jobs/job-registry.js +55 -0
- package/build/src/background-jobs/job-runner.d.ts +6 -0
- package/build/src/background-jobs/job-runner.d.ts.map +1 -0
- package/build/src/background-jobs/job-runner.js +44 -0
- package/build/src/background-jobs/job.d.ts +35 -0
- package/build/src/background-jobs/job.d.ts.map +1 -0
- package/build/src/background-jobs/job.js +61 -0
- package/build/src/background-jobs/json-socket.d.ts +27 -0
- package/build/src/background-jobs/json-socket.d.ts.map +1 -0
- package/build/src/background-jobs/json-socket.js +55 -0
- package/build/src/background-jobs/main.d.ts +62 -0
- package/build/src/background-jobs/main.d.ts.map +1 -0
- package/build/src/background-jobs/main.js +216 -0
- package/build/src/background-jobs/status-reporter.d.ts +54 -0
- package/build/src/background-jobs/status-reporter.d.ts.map +1 -0
- package/build/src/background-jobs/status-reporter.js +113 -0
- package/build/src/background-jobs/store.d.ts +237 -0
- package/build/src/background-jobs/store.d.ts.map +1 -0
- package/build/src/background-jobs/store.js +488 -0
- package/build/src/background-jobs/types.d.ts +17 -0
- package/build/src/background-jobs/types.d.ts.map +1 -0
- package/build/src/background-jobs/types.js +8 -0
- package/build/src/background-jobs/worker.d.ts +64 -0
- package/build/src/background-jobs/worker.d.ts.map +1 -0
- package/build/src/background-jobs/worker.js +155 -0
- package/build/src/cli/commands/background-jobs-main.d.ts +5 -0
- package/build/src/cli/commands/background-jobs-main.d.ts.map +1 -0
- package/build/src/cli/commands/background-jobs-main.js +19 -0
- package/build/src/cli/commands/background-jobs-runner.d.ts +5 -0
- package/build/src/cli/commands/background-jobs-runner.d.ts.map +1 -0
- package/build/src/cli/commands/background-jobs-runner.js +14 -0
- package/build/src/cli/commands/background-jobs-worker.d.ts +5 -0
- package/build/src/cli/commands/background-jobs-worker.d.ts.map +1 -0
- package/build/src/cli/commands/background-jobs-worker.js +19 -0
- package/build/src/configuration-types.d.ts +25 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +8 -1
- package/build/src/configuration.d.ts +11 -1
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +26 -2
- package/build/src/database/drivers/mssql/sql/update.js +3 -3
- package/build/src/database/drivers/mysql/sql/update.js +3 -3
- package/build/src/database/drivers/pgsql/sql/update.js +3 -3
- package/build/src/database/drivers/sqlite/sql/update.js +3 -3
- package/build/src/database/query/update-base.d.ts +5 -0
- package/build/src/database/query/update-base.d.ts.map +1 -1
- package/build/src/database/query/update-base.js +10 -1
- package/build/src/database/query-parser/limit-parser.d.ts.map +1 -1
- package/build/src/database/query-parser/limit-parser.js +8 -7
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +6 -4
- package/build/src/testing/base-expect.d.ts +13 -0
- package/build/src/testing/base-expect.d.ts.map +1 -0
- package/build/src/testing/base-expect.js +14 -0
- package/build/src/testing/expect-to-change.d.ts +27 -0
- package/build/src/testing/expect-to-change.d.ts.map +1 -0
- package/build/src/testing/expect-to-change.js +43 -0
- package/build/src/testing/expect-utils.d.ts +45 -0
- package/build/src/testing/expect-utils.d.ts.map +1 -0
- package/build/src/testing/expect-utils.js +190 -0
- package/build/src/testing/expect.d.ts +137 -0
- package/build/src/testing/expect.d.ts.map +1 -0
- package/build/src/testing/expect.js +619 -0
- package/build/src/testing/test.d.ts +4 -157
- package/build/src/testing/test.d.ts.map +1 -1
- package/build/src/testing/test.js +3 -678
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { randomUUID } from "crypto";
|
|
3
|
+
import { Logger } from "../logger.js";
|
|
4
|
+
import TableData from "../database/table-data/index.js";
|
|
5
|
+
import BackgroundJobRecord from "./job-record.js";
|
|
6
|
+
const MIGRATIONS_TABLE = "velocious_internal_migrations";
|
|
7
|
+
const MIGRATION_SCOPE = "background_jobs";
|
|
8
|
+
const MIGRATION_VERSION = "20250215000000";
|
|
9
|
+
const JOBS_TABLE = "background_jobs";
|
|
10
|
+
const DEFAULT_MAX_RETRIES = 10;
|
|
11
|
+
const ORPHANED_AFTER_MS = 2 * 60 * 60 * 1000;
|
|
12
|
+
export default class BackgroundJobsStore {
|
|
13
|
+
/**
|
|
14
|
+
* @param {object} args - Options.
|
|
15
|
+
* @param {import("../configuration.js").default} args.configuration - Configuration.
|
|
16
|
+
* @param {string} [args.databaseIdentifier] - Database identifier.
|
|
17
|
+
*/
|
|
18
|
+
constructor({ configuration, databaseIdentifier }) {
|
|
19
|
+
this.configuration = configuration;
|
|
20
|
+
this.databaseIdentifier = databaseIdentifier;
|
|
21
|
+
this.logger = new Logger(this);
|
|
22
|
+
this._readyPromise = null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* @returns {string} - Database identifier.
|
|
26
|
+
*/
|
|
27
|
+
getDatabaseIdentifier() {
|
|
28
|
+
if (this.databaseIdentifier)
|
|
29
|
+
return this.databaseIdentifier;
|
|
30
|
+
return this.configuration.getBackgroundJobsConfig().databaseIdentifier;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* @returns {Promise<void>} - Resolves when ready.
|
|
34
|
+
*/
|
|
35
|
+
async ensureReady() {
|
|
36
|
+
if (this._readyPromise)
|
|
37
|
+
return await this._readyPromise;
|
|
38
|
+
this._readyPromise = (async () => {
|
|
39
|
+
this.configuration.setCurrent();
|
|
40
|
+
await this._ensureSchema();
|
|
41
|
+
await this._initializeModel();
|
|
42
|
+
})();
|
|
43
|
+
try {
|
|
44
|
+
await this._readyPromise;
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
this._readyPromise = null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* @param {object} args - Options.
|
|
52
|
+
* @param {string} args.jobName - Job name.
|
|
53
|
+
* @param {any[]} args.args - Arguments.
|
|
54
|
+
* @param {import("./types.js").BackgroundJobOptions} [args.options] - Options.
|
|
55
|
+
* @returns {Promise<string>} - Job id.
|
|
56
|
+
*/
|
|
57
|
+
async enqueue({ jobName, args, options }) {
|
|
58
|
+
await this.ensureReady();
|
|
59
|
+
const jobId = randomUUID();
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
const forked = options?.forked !== false;
|
|
62
|
+
const maxRetries = this._normalizeMaxRetries(options?.maxRetries);
|
|
63
|
+
const argsJson = JSON.stringify(args || []);
|
|
64
|
+
await this._withDb(async (db) => {
|
|
65
|
+
await db.insert({
|
|
66
|
+
tableName: JOBS_TABLE,
|
|
67
|
+
data: {
|
|
68
|
+
id: jobId,
|
|
69
|
+
job_name: jobName,
|
|
70
|
+
args_json: argsJson,
|
|
71
|
+
forked,
|
|
72
|
+
max_retries: maxRetries,
|
|
73
|
+
attempts: 0,
|
|
74
|
+
status: "queued",
|
|
75
|
+
scheduled_at_ms: now,
|
|
76
|
+
created_at_ms: now
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
return jobId;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* @returns {Promise<import("./store.js").BackgroundJobRow | null>} - Next job.
|
|
84
|
+
*/
|
|
85
|
+
async nextAvailableJob() {
|
|
86
|
+
await this.ensureReady();
|
|
87
|
+
return await this._withDb(async (db) => {
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
const query = db
|
|
90
|
+
.newQuery()
|
|
91
|
+
.from(JOBS_TABLE)
|
|
92
|
+
.where({ status: "queued" })
|
|
93
|
+
.where(`scheduled_at_ms <= ${db.quote(now)}`)
|
|
94
|
+
.order("scheduled_at_ms ASC")
|
|
95
|
+
.order("created_at_ms ASC")
|
|
96
|
+
.limit(1);
|
|
97
|
+
const rows = await query.results();
|
|
98
|
+
const row = rows[0];
|
|
99
|
+
if (!row)
|
|
100
|
+
return null;
|
|
101
|
+
return this._normalizeJobRow(row);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* @param {string} jobId - Job id.
|
|
106
|
+
* @returns {Promise<import("./store.js").BackgroundJobRow | null>} - Job row.
|
|
107
|
+
*/
|
|
108
|
+
async getJob(jobId) {
|
|
109
|
+
await this.ensureReady();
|
|
110
|
+
return await this._withDb(async (db) => {
|
|
111
|
+
const query = db
|
|
112
|
+
.newQuery()
|
|
113
|
+
.from(JOBS_TABLE)
|
|
114
|
+
.where({ id: jobId })
|
|
115
|
+
.limit(1);
|
|
116
|
+
const rows = await query.results();
|
|
117
|
+
const row = rows[0];
|
|
118
|
+
if (!row)
|
|
119
|
+
return null;
|
|
120
|
+
return this._normalizeJobRow(row);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* @param {object} args - Options.
|
|
125
|
+
* @param {string} args.jobId - Job id.
|
|
126
|
+
* @param {string} [args.workerId] - Worker id.
|
|
127
|
+
* @returns {Promise<number>} - Resolves with handed off timestamp.
|
|
128
|
+
*/
|
|
129
|
+
async markHandedOff({ jobId, workerId }) {
|
|
130
|
+
await this.ensureReady();
|
|
131
|
+
const handedOffAtMs = Date.now();
|
|
132
|
+
await this._withDb(async (db) => {
|
|
133
|
+
await db.update({
|
|
134
|
+
tableName: JOBS_TABLE,
|
|
135
|
+
data: {
|
|
136
|
+
status: "handed_off",
|
|
137
|
+
handed_off_at_ms: handedOffAtMs,
|
|
138
|
+
worker_id: workerId || null
|
|
139
|
+
},
|
|
140
|
+
conditions: { id: jobId }
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
return handedOffAtMs;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* @param {object} args - Options.
|
|
147
|
+
* @param {string} args.jobId - Job id.
|
|
148
|
+
* @param {string} [args.workerId] - Worker id.
|
|
149
|
+
* @param {number} [args.handedOffAtMs] - Handed off timestamp.
|
|
150
|
+
* @returns {Promise<void>} - Resolves when updated.
|
|
151
|
+
*/
|
|
152
|
+
async markCompleted({ jobId, workerId, handedOffAtMs }) {
|
|
153
|
+
await this.ensureReady();
|
|
154
|
+
await this._withDb(async (db) => {
|
|
155
|
+
const job = await this._getJobRowById(db, jobId);
|
|
156
|
+
if (!job)
|
|
157
|
+
return;
|
|
158
|
+
if (!this._shouldAcceptReport({ job, workerId, handedOffAtMs }))
|
|
159
|
+
return;
|
|
160
|
+
await db.update({
|
|
161
|
+
tableName: JOBS_TABLE,
|
|
162
|
+
data: {
|
|
163
|
+
status: "completed",
|
|
164
|
+
completed_at_ms: Date.now()
|
|
165
|
+
},
|
|
166
|
+
conditions: { id: jobId }
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* @param {object} args - Options.
|
|
172
|
+
* @param {string} args.jobId - Job id.
|
|
173
|
+
* @returns {Promise<void>} - Resolves when updated.
|
|
174
|
+
*/
|
|
175
|
+
async markReturnedToQueue({ jobId }) {
|
|
176
|
+
await this.ensureReady();
|
|
177
|
+
await this._withDb(async (db) => {
|
|
178
|
+
await db.update({
|
|
179
|
+
tableName: JOBS_TABLE,
|
|
180
|
+
data: {
|
|
181
|
+
status: "queued",
|
|
182
|
+
scheduled_at_ms: Date.now(),
|
|
183
|
+
handed_off_at_ms: null,
|
|
184
|
+
worker_id: null
|
|
185
|
+
},
|
|
186
|
+
conditions: { id: jobId }
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* @param {object} args - Options.
|
|
192
|
+
* @param {string} args.jobId - Job id.
|
|
193
|
+
* @param {unknown} args.error - Error.
|
|
194
|
+
* @param {string} [args.workerId] - Worker id.
|
|
195
|
+
* @param {number} [args.handedOffAtMs] - Handed off timestamp.
|
|
196
|
+
* @returns {Promise<void>} - Resolves when updated.
|
|
197
|
+
*/
|
|
198
|
+
async markFailed({ jobId, error, workerId, handedOffAtMs }) {
|
|
199
|
+
await this.ensureReady();
|
|
200
|
+
await this._withDb(async (db) => {
|
|
201
|
+
const job = await this._getJobRowById(db, jobId);
|
|
202
|
+
if (!job)
|
|
203
|
+
return;
|
|
204
|
+
if (!this._shouldAcceptReport({ job, workerId, handedOffAtMs }))
|
|
205
|
+
return;
|
|
206
|
+
await this._applyFailure({ db, job, error, markOrphaned: false });
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* @param {object} [args] - Options.
|
|
211
|
+
* @param {number} [args.orphanedAfterMs] - Mark jobs orphaned after this duration.
|
|
212
|
+
* @returns {Promise<number>} - Count of orphaned jobs.
|
|
213
|
+
*/
|
|
214
|
+
async markOrphanedJobs({ orphanedAfterMs = ORPHANED_AFTER_MS } = {}) {
|
|
215
|
+
await this.ensureReady();
|
|
216
|
+
return await this._withDb(async (db) => {
|
|
217
|
+
const cutoff = Date.now() - orphanedAfterMs;
|
|
218
|
+
const query = db
|
|
219
|
+
.newQuery()
|
|
220
|
+
.from(JOBS_TABLE)
|
|
221
|
+
.where({ status: "handed_off" })
|
|
222
|
+
.where(`handed_off_at_ms <= ${db.quote(cutoff)}`);
|
|
223
|
+
const rows = await query.results();
|
|
224
|
+
for (const row of rows) {
|
|
225
|
+
const job = this._normalizeJobRow(row);
|
|
226
|
+
await this._applyFailure({
|
|
227
|
+
db,
|
|
228
|
+
job,
|
|
229
|
+
error: "Job orphaned after timeout",
|
|
230
|
+
markOrphaned: true
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return rows.length;
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* @returns {Promise<void>} - Resolves when cleared.
|
|
238
|
+
*/
|
|
239
|
+
async clearAll() {
|
|
240
|
+
await this.ensureReady();
|
|
241
|
+
await this._withDb(async (db) => {
|
|
242
|
+
await db.query(`DELETE FROM ${db.quoteTable(JOBS_TABLE)}`);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* @param {number} retryCount - Retry attempt count (1-based).
|
|
247
|
+
* @returns {number} - Delay in milliseconds.
|
|
248
|
+
*/
|
|
249
|
+
getRetryDelayMs(retryCount) {
|
|
250
|
+
const scheduleSeconds = [10, 60, 600, 3600];
|
|
251
|
+
if (retryCount <= scheduleSeconds.length) {
|
|
252
|
+
return scheduleSeconds[retryCount - 1] * 1000;
|
|
253
|
+
}
|
|
254
|
+
return (retryCount - 3) * 60 * 60 * 1000;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* @param {number | undefined} maxRetries - Input.
|
|
258
|
+
* @returns {number} - Normalized max retries.
|
|
259
|
+
*/
|
|
260
|
+
_normalizeMaxRetries(maxRetries) {
|
|
261
|
+
if (typeof maxRetries === "number" && Number.isFinite(maxRetries) && maxRetries >= 0) {
|
|
262
|
+
return Math.floor(maxRetries);
|
|
263
|
+
}
|
|
264
|
+
return DEFAULT_MAX_RETRIES;
|
|
265
|
+
}
|
|
266
|
+
async _ensureSchema() {
|
|
267
|
+
await this._withDb(async (db) => {
|
|
268
|
+
await this._ensureMigrationsTable(db);
|
|
269
|
+
const alreadyApplied = await this._hasMigration(db);
|
|
270
|
+
if (alreadyApplied)
|
|
271
|
+
return;
|
|
272
|
+
await this._applyMigrations(db);
|
|
273
|
+
await db.insert({
|
|
274
|
+
tableName: MIGRATIONS_TABLE,
|
|
275
|
+
data: {
|
|
276
|
+
key: this._migrationKey(),
|
|
277
|
+
scope: MIGRATION_SCOPE,
|
|
278
|
+
version: MIGRATION_VERSION,
|
|
279
|
+
applied_at_ms: Date.now()
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
async _ensureMigrationsTable(db) {
|
|
285
|
+
if (await db.tableExists(MIGRATIONS_TABLE))
|
|
286
|
+
return;
|
|
287
|
+
const table = new TableData(MIGRATIONS_TABLE, { ifNotExists: true });
|
|
288
|
+
table.string("key", { null: false, primaryKey: true });
|
|
289
|
+
table.string("scope", { null: false });
|
|
290
|
+
table.string("version", { null: false });
|
|
291
|
+
table.bigint("applied_at_ms", { null: false });
|
|
292
|
+
await db.createTable(table);
|
|
293
|
+
}
|
|
294
|
+
async _hasMigration(db) {
|
|
295
|
+
const query = db
|
|
296
|
+
.newQuery()
|
|
297
|
+
.from(MIGRATIONS_TABLE)
|
|
298
|
+
.where({ key: this._migrationKey() })
|
|
299
|
+
.limit(1);
|
|
300
|
+
const rows = await query.results();
|
|
301
|
+
return rows.length > 0;
|
|
302
|
+
}
|
|
303
|
+
async _applyMigrations(db) {
|
|
304
|
+
this.logger.info("Applying background jobs schema");
|
|
305
|
+
if (await db.tableExists(JOBS_TABLE)) {
|
|
306
|
+
this.logger.info("Background jobs table already exists - skipping create");
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const table = new TableData(JOBS_TABLE, { ifNotExists: true });
|
|
310
|
+
table.string("id", { primaryKey: true });
|
|
311
|
+
table.string("job_name", { null: false, index: true });
|
|
312
|
+
table.text("args_json", { null: false });
|
|
313
|
+
table.boolean("forked", { null: false });
|
|
314
|
+
table.integer("max_retries", { null: false });
|
|
315
|
+
table.integer("attempts", { null: false });
|
|
316
|
+
table.string("status", { null: false, index: true });
|
|
317
|
+
table.bigint("scheduled_at_ms", { null: false, index: true });
|
|
318
|
+
table.bigint("created_at_ms", { null: false, index: true });
|
|
319
|
+
table.bigint("handed_off_at_ms", { null: true, index: true });
|
|
320
|
+
table.bigint("completed_at_ms", { null: true });
|
|
321
|
+
table.bigint("failed_at_ms", { null: true });
|
|
322
|
+
table.bigint("orphaned_at_ms", { null: true, index: true });
|
|
323
|
+
table.string("worker_id", { null: true });
|
|
324
|
+
table.text("last_error", { null: true });
|
|
325
|
+
await db.createTable(table);
|
|
326
|
+
}
|
|
327
|
+
async _initializeModel() {
|
|
328
|
+
BackgroundJobRecord.setDatabaseIdentifier(this.getDatabaseIdentifier());
|
|
329
|
+
if (BackgroundJobRecord.isInitialized())
|
|
330
|
+
return;
|
|
331
|
+
const pool = this.configuration.getDatabasePool(this.getDatabaseIdentifier());
|
|
332
|
+
await pool.withConnection(async () => {
|
|
333
|
+
await BackgroundJobRecord.initializeRecord({ configuration: this.configuration });
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
async _getJobRowById(db, jobId) {
|
|
337
|
+
const query = db
|
|
338
|
+
.newQuery()
|
|
339
|
+
.from(JOBS_TABLE)
|
|
340
|
+
.where({ id: jobId })
|
|
341
|
+
.limit(1);
|
|
342
|
+
const rows = await query.results();
|
|
343
|
+
if (!rows[0])
|
|
344
|
+
return null;
|
|
345
|
+
return this._normalizeJobRow(rows[0]);
|
|
346
|
+
}
|
|
347
|
+
async _applyFailure({ db, job, error, markOrphaned }) {
|
|
348
|
+
const now = Date.now();
|
|
349
|
+
const nextAttempt = (job.attempts || 0) + 1;
|
|
350
|
+
const maxRetries = this._normalizeMaxRetries(job.maxRetries);
|
|
351
|
+
const shouldRetry = nextAttempt <= maxRetries;
|
|
352
|
+
const failureMessage = this._normalizeError(error);
|
|
353
|
+
const scheduledAt = shouldRetry ? now + this.getRetryDelayMs(nextAttempt) : job.scheduledAtMs;
|
|
354
|
+
/** @type {Record<string, any>} */
|
|
355
|
+
const update = {
|
|
356
|
+
attempts: nextAttempt,
|
|
357
|
+
handed_off_at_ms: null,
|
|
358
|
+
worker_id: null,
|
|
359
|
+
last_error: failureMessage
|
|
360
|
+
};
|
|
361
|
+
if (markOrphaned) {
|
|
362
|
+
update.orphaned_at_ms = now;
|
|
363
|
+
}
|
|
364
|
+
if (shouldRetry) {
|
|
365
|
+
update.status = "queued";
|
|
366
|
+
update.scheduled_at_ms = scheduledAt;
|
|
367
|
+
}
|
|
368
|
+
else if (markOrphaned) {
|
|
369
|
+
update.status = "orphaned";
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
update.status = "failed";
|
|
373
|
+
update.failed_at_ms = now;
|
|
374
|
+
}
|
|
375
|
+
await db.update({
|
|
376
|
+
tableName: JOBS_TABLE,
|
|
377
|
+
data: update,
|
|
378
|
+
conditions: { id: job.id }
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
_normalizeJobRow(row) {
|
|
382
|
+
return {
|
|
383
|
+
id: String(row.id),
|
|
384
|
+
jobName: String(row.job_name),
|
|
385
|
+
args: this._parseArgs(row.args_json),
|
|
386
|
+
forked: this._normalizeBoolean(row.forked),
|
|
387
|
+
status: row.status ? String(row.status) : "queued",
|
|
388
|
+
attempts: this._normalizeNumber(row.attempts),
|
|
389
|
+
maxRetries: this._normalizeNumber(row.max_retries),
|
|
390
|
+
scheduledAtMs: this._normalizeNumber(row.scheduled_at_ms),
|
|
391
|
+
createdAtMs: this._normalizeNumber(row.created_at_ms),
|
|
392
|
+
handedOffAtMs: this._normalizeNumber(row.handed_off_at_ms),
|
|
393
|
+
completedAtMs: this._normalizeNumber(row.completed_at_ms),
|
|
394
|
+
failedAtMs: this._normalizeNumber(row.failed_at_ms),
|
|
395
|
+
orphanedAtMs: this._normalizeNumber(row.orphaned_at_ms),
|
|
396
|
+
workerId: row.worker_id ? String(row.worker_id) : null,
|
|
397
|
+
lastError: row.last_error ? String(row.last_error) : null
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
_normalizeNumber(value) {
|
|
401
|
+
if (value === null || value === undefined || value === "")
|
|
402
|
+
return null;
|
|
403
|
+
const numeric = Number(value);
|
|
404
|
+
if (Number.isNaN(numeric))
|
|
405
|
+
return null;
|
|
406
|
+
return numeric;
|
|
407
|
+
}
|
|
408
|
+
_normalizeBoolean(value) {
|
|
409
|
+
if (value === null || value === undefined)
|
|
410
|
+
return false;
|
|
411
|
+
if (typeof value === "boolean")
|
|
412
|
+
return value;
|
|
413
|
+
if (typeof value === "number")
|
|
414
|
+
return value !== 0;
|
|
415
|
+
return value === "true";
|
|
416
|
+
}
|
|
417
|
+
_parseArgs(value) {
|
|
418
|
+
if (!value)
|
|
419
|
+
return [];
|
|
420
|
+
try {
|
|
421
|
+
const parsed = JSON.parse(String(value));
|
|
422
|
+
if (Array.isArray(parsed))
|
|
423
|
+
return parsed;
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
// Ignore parse errors.
|
|
427
|
+
}
|
|
428
|
+
return [];
|
|
429
|
+
}
|
|
430
|
+
_normalizeError(error) {
|
|
431
|
+
if (error instanceof Error)
|
|
432
|
+
return error.stack || error.message;
|
|
433
|
+
if (typeof error === "string")
|
|
434
|
+
return error;
|
|
435
|
+
try {
|
|
436
|
+
return JSON.stringify(error);
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
return String(error);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
async _withDb(callback) {
|
|
443
|
+
const pool = this.configuration.getDatabasePool(this.getDatabaseIdentifier());
|
|
444
|
+
let result;
|
|
445
|
+
await pool.withConnection(async (db) => {
|
|
446
|
+
result = await callback(db);
|
|
447
|
+
});
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* @param {object} args - Options.
|
|
452
|
+
* @param {import("./store.js").BackgroundJobRow} args.job - Job row.
|
|
453
|
+
* @param {string | null | undefined} args.workerId - Worker id from report.
|
|
454
|
+
* @param {number | null | undefined} args.handedOffAtMs - Handed off timestamp from report.
|
|
455
|
+
* @returns {boolean} - Whether to accept the report.
|
|
456
|
+
*/
|
|
457
|
+
_shouldAcceptReport({ job, workerId, handedOffAtMs }) {
|
|
458
|
+
if (job.status !== "handed_off")
|
|
459
|
+
return false;
|
|
460
|
+
if (workerId && job.workerId && workerId !== job.workerId)
|
|
461
|
+
return false;
|
|
462
|
+
if (handedOffAtMs && job.handedOffAtMs && handedOffAtMs !== job.handedOffAtMs)
|
|
463
|
+
return false;
|
|
464
|
+
return true;
|
|
465
|
+
}
|
|
466
|
+
_migrationKey() {
|
|
467
|
+
return `${MIGRATION_SCOPE}:${MIGRATION_VERSION}`;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* @typedef {object} BackgroundJobRow
|
|
472
|
+
* @property {string} id - Job id.
|
|
473
|
+
* @property {string} jobName - Job class name.
|
|
474
|
+
* @property {any[]} args - Serialized job arguments.
|
|
475
|
+
* @property {boolean} forked - Whether the job is forked.
|
|
476
|
+
* @property {string} status - Current job status.
|
|
477
|
+
* @property {number | null} attempts - Failure attempts count.
|
|
478
|
+
* @property {number | null} maxRetries - Max retry attempts.
|
|
479
|
+
* @property {number | null} scheduledAtMs - Next scheduled time in ms.
|
|
480
|
+
* @property {number | null} createdAtMs - Creation time in ms.
|
|
481
|
+
* @property {number | null} handedOffAtMs - Time handed to worker in ms.
|
|
482
|
+
* @property {number | null} completedAtMs - Completion time in ms.
|
|
483
|
+
* @property {number | null} failedAtMs - Failure time in ms.
|
|
484
|
+
* @property {number | null} orphanedAtMs - Orphaned time in ms.
|
|
485
|
+
* @property {string | null} workerId - Worker id handling the job.
|
|
486
|
+
* @property {string | null} lastError - Last failure message.
|
|
487
|
+
*/
|
|
488
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYmFja2dyb3VuZC1qb2JzL3N0b3JlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sUUFBUSxDQUFBO0FBQ2pDLE9BQU8sRUFBQyxNQUFNLEVBQUMsTUFBTSxjQUFjLENBQUE7QUFDbkMsT0FBTyxTQUFTLE1BQU0saUNBQWlDLENBQUE7QUFDdkQsT0FBTyxtQkFBbUIsTUFBTSxpQkFBaUIsQ0FBQTtBQUVqRCxNQUFNLGdCQUFnQixHQUFHLCtCQUErQixDQUFBO0FBQ3hELE1BQU0sZUFBZSxHQUFHLGlCQUFpQixDQUFBO0FBQ3pDLE1BQU0saUJBQWlCLEdBQUcsZ0JBQWdCLENBQUE7QUFDMUMsTUFBTSxVQUFVLEdBQUcsaUJBQWlCLENBQUE7QUFDcEMsTUFBTSxtQkFBbUIsR0FBRyxFQUFFLENBQUE7QUFDOUIsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUE7QUFFNUMsTUFBTSxDQUFDLE9BQU8sT0FBTyxtQkFBbUI7SUFDdEM7Ozs7T0FJRztJQUNILFlBQVksRUFBQyxhQUFhLEVBQUUsa0JBQWtCLEVBQUM7UUFDN0MsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUE7UUFDbEMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGtCQUFrQixDQUFBO1FBQzVDLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDOUIsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUE7SUFDM0IsQ0FBQztJQUVEOztPQUVHO0lBQ0gscUJBQXFCO1FBQ25CLElBQUksSUFBSSxDQUFDLGtCQUFrQjtZQUFFLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFBO1FBRTNELE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyx1QkFBdUIsRUFB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QU8sQ0FBQyxRQUFRO1FBQ3BCLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLENBQUE7UUFDN0UsSUFBSSxNQUFNLENBQUE7UUFFVixNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFO1lBQ3JDLE1BQU0sR0FBRyxNQUFNLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUM3QixDQUFDLENBQUMsQ0FBQTtRQUVGLE9BQU8sTUFBTSxDQUFBO0lBQ2YsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILG1CQUFtQixDQUFDLEVBQUMsR0FBRyxFQUFFLFFBQVEsRUFBRSxhQUFhLEVBQUM7UUFDaEQsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLFlBQVk7WUFBRSxPQUFPLEtBQUssQ0FBQTtRQUU3QyxJQUFJLFFBQVEsSUFBSSxHQUFHLENBQUMsUUFBUSxJQUFJLFFBQVEsS0FBSyxHQUFHLENBQUMsUUFBUTtZQUFFLE9BQU8sS0FBSyxDQUFBO1FBRXZFLElBQUksYUFBYSxJQUFJLEdBQUcsQ0FBQyxhQUFhLElBQUksYUFBYSxLQUFLLEdBQUcsQ0FBQyxhQUFhO1lBQUUsT0FBTyxLQUFLLENBQUE7UUFFM0YsT0FBTyxJQUFJLENBQUE7SUFDYixDQUFDO0lBRUQsYUFBYTtRQUNYLE9BQU8sR0FBRyxlQUFlLElBQUksaUJBQWlCLEVBQUUsQ0FBQTtJQUNsRCxDQUFDO0NBQ0Y7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkciLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IHtyYW5kb21VVUlEfSBmcm9tIFwiY3J5cHRvXCJcbmltcG9ydCB7TG9nZ2VyfSBmcm9tIFwiLi4vbG9nZ2VyLmpzXCJcbmltcG9ydCBUYWJsZURhdGEgZnJvbSBcIi4uL2RhdGFiYXNlL3RhYmxlLWRhdGEvaW5kZXguanNcIlxuaW1wb3J0IEJhY2tncm91bmRKb2JSZWNvcmQgZnJvbSBcIi4vam9iLXJlY29yZC5qc1wiXG5cbmNvbnN0IE1JR1JBVElPTlNfVEFCTEUgPSBcInZlbG9jaW91c19pbnRlcm5hbF9taWdyYXRpb25zXCJcbmNvbnN0IE1JR1JBVElPTl9TQ09QRSA9IFwiYmFja2dyb3VuZF9qb2JzXCJcbmNvbnN0IE1JR1JBVElPTl9WRVJTSU9OID0gXCIyMDI1MDIxNTAwMDAwMFwiXG5jb25zdCBKT0JTX1RBQkxFID0gXCJiYWNrZ3JvdW5kX2pvYnNcIlxuY29uc3QgREVGQVVMVF9NQVhfUkVUUklFUyA9IDEwXG5jb25zdCBPUlBIQU5FRF9BRlRFUl9NUyA9IDIgKiA2MCAqIDYwICogMTAwMFxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBCYWNrZ3JvdW5kSm9ic1N0b3JlIHtcbiAgLyoqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9IGFyZ3MuY29uZmlndXJhdGlvbiAtIENvbmZpZ3VyYXRpb24uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5kYXRhYmFzZUlkZW50aWZpZXJdIC0gRGF0YWJhc2UgaWRlbnRpZmllci5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHtjb25maWd1cmF0aW9uLCBkYXRhYmFzZUlkZW50aWZpZXJ9KSB7XG4gICAgdGhpcy5jb25maWd1cmF0aW9uID0gY29uZmlndXJhdGlvblxuICAgIHRoaXMuZGF0YWJhc2VJZGVudGlmaWVyID0gZGF0YWJhc2VJZGVudGlmaWVyXG4gICAgdGhpcy5sb2dnZXIgPSBuZXcgTG9nZ2VyKHRoaXMpXG4gICAgdGhpcy5fcmVhZHlQcm9taXNlID0gbnVsbFxuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gRGF0YWJhc2UgaWRlbnRpZmllci5cbiAgICovXG4gIGdldERhdGFiYXNlSWRlbnRpZmllcigpIHtcbiAgICBpZiAodGhpcy5kYXRhYmFzZUlkZW50aWZpZXIpIHJldHVybiB0aGlzLmRhdGFiYXNlSWRlbnRpZmllclxuXG4gICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbi5nZXRCYWNrZ3JvdW5kSm9ic0NvbmZpZygpLmRhdGFiYXNlSWRlbnRpZmllclxuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gcmVhZHkuXG4gICAqL1xuICBhc3luYyBlbnN1cmVSZWFkeSgpIHtcbiAgICBpZiAodGhpcy5fcmVhZHlQcm9taXNlKSByZXR1cm4gYXdhaXQgdGhpcy5fcmVhZHlQcm9taXNlXG5cbiAgICB0aGlzLl9yZWFkeVByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5jb25maWd1cmF0aW9uLnNldEN1cnJlbnQoKVxuICAgICAgYXdhaXQgdGhpcy5fZW5zdXJlU2NoZW1hKClcbiAgICAgIGF3YWl0IHRoaXMuX2luaXRpYWxpemVNb2RlbCgpXG4gICAgfSkoKVxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuX3JlYWR5UHJvbWlzZVxuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLl9yZWFkeVByb21pc2UgPSBudWxsXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muam9iTmFtZSAtIEpvYiBuYW1lLlxuICAgKiBAcGFyYW0ge2FueVtdfSBhcmdzLmFyZ3MgLSBBcmd1bWVudHMuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iT3B0aW9uc30gW2FyZ3Mub3B0aW9uc10gLSBPcHRpb25zLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSAtIEpvYiBpZC5cbiAgICovXG4gIGFzeW5jIGVucXVldWUoe2pvYk5hbWUsIGFyZ3MsIG9wdGlvbnN9KSB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpXG5cbiAgICBjb25zdCBqb2JJZCA9IHJhbmRvbVVVSUQoKVxuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KClcbiAgICBjb25zdCBmb3JrZWQgPSBvcHRpb25zPy5mb3JrZWQgIT09IGZhbHNlXG4gICAgY29uc3QgbWF4UmV0cmllcyA9IHRoaXMuX25vcm1hbGl6ZU1heFJldHJpZXMob3B0aW9ucz8ubWF4UmV0cmllcylcbiAgICBjb25zdCBhcmdzSnNvbiA9IEpTT04uc3RyaW5naWZ5KGFyZ3MgfHwgW10pXG5cbiAgICBhd2FpdCB0aGlzLl93aXRoRGIoYXN5bmMgKGRiKSA9PiB7XG4gICAgICBhd2FpdCBkYi5pbnNlcnQoe1xuICAgICAgICB0YWJsZU5hbWU6IEpPQlNfVEFCTEUsXG4gICAgICAgIGRhdGE6IHtcbiAgICAgICAgICBpZDogam9iSWQsXG4gICAgICAgICAgam9iX25hbWU6IGpvYk5hbWUsXG4gICAgICAgICAgYXJnc19qc29uOiBhcmdzSnNvbixcbiAgICAgICAgICBmb3JrZWQsXG4gICAgICAgICAgbWF4X3JldHJpZXM6IG1heFJldHJpZXMsXG4gICAgICAgICAgYXR0ZW1wdHM6IDAsXG4gICAgICAgICAgc3RhdHVzOiBcInF1ZXVlZFwiLFxuICAgICAgICAgIHNjaGVkdWxlZF9hdF9tczogbm93LFxuICAgICAgICAgIGNyZWF0ZWRfYXRfbXM6IG5vd1xuICAgICAgICB9XG4gICAgICB9KVxuICAgIH0pXG5cbiAgICByZXR1cm4gam9iSWRcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3N0b3JlLmpzXCIpLkJhY2tncm91bmRKb2JSb3cgfCBudWxsPn0gLSBOZXh0IGpvYi5cbiAgICovXG4gIGFzeW5jIG5leHRBdmFpbGFibGVKb2IoKSB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpXG5cbiAgICByZXR1cm4gYXdhaXQgdGhpcy5fd2l0aERiKGFzeW5jIChkYikgPT4ge1xuICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKVxuICAgICAgY29uc3QgcXVlcnkgPSBkYlxuICAgICAgICAubmV3UXVlcnkoKVxuICAgICAgICAuZnJvbShKT0JTX1RBQkxFKVxuICAgICAgICAud2hlcmUoe3N0YXR1czogXCJxdWV1ZWRcIn0pXG4gICAgICAgIC53aGVyZShgc2NoZWR1bGVkX2F0X21zIDw9ICR7ZGIucXVvdGUobm93KX1gKVxuICAgICAgICAub3JkZXIoXCJzY2hlZHVsZWRfYXRfbXMgQVNDXCIpXG4gICAgICAgIC5vcmRlcihcImNyZWF0ZWRfYXRfbXMgQVNDXCIpXG4gICAgICAgIC5saW1pdCgxKVxuXG4gICAgICBjb25zdCByb3dzID0gYXdhaXQgcXVlcnkucmVzdWx0cygpXG4gICAgICBjb25zdCByb3cgPSByb3dzWzBdXG5cbiAgICAgIGlmICghcm93KSByZXR1cm4gbnVsbFxuXG4gICAgICByZXR1cm4gdGhpcy5fbm9ybWFsaXplSm9iUm93KHJvdylcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBqb2JJZCAtIEpvYiBpZC5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi9zdG9yZS5qc1wiKS5CYWNrZ3JvdW5kSm9iUm93IHwgbnVsbD59IC0gSm9iIHJvdy5cbiAgICovXG4gIGFzeW5jIGdldEpvYihqb2JJZCkge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKVxuXG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuX3dpdGhEYihhc3luYyAoZGIpID0+IHtcbiAgICAgIGNvbnN0IHF1ZXJ5ID0gZGJcbiAgICAgICAgLm5ld1F1ZXJ5KClcbiAgICAgICAgLmZyb20oSk9CU19UQUJMRSlcbiAgICAgICAgLndoZXJlKHtpZDogam9iSWR9KVxuICAgICAgICAubGltaXQoMSlcblxuICAgICAgY29uc3Qgcm93cyA9IGF3YWl0IHF1ZXJ5LnJlc3VsdHMoKVxuICAgICAgY29uc3Qgcm93ID0gcm93c1swXVxuXG4gICAgICBpZiAoIXJvdykgcmV0dXJuIG51bGxcblxuICAgICAgcmV0dXJuIHRoaXMuX25vcm1hbGl6ZUpvYlJvdyhyb3cpXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmpvYklkIC0gSm9iIGlkLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3Mud29ya2VySWRdIC0gV29ya2VyIGlkLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxudW1iZXI+fSAtIFJlc29sdmVzIHdpdGggaGFuZGVkIG9mZiB0aW1lc3RhbXAuXG4gICAqL1xuICBhc3luYyBtYXJrSGFuZGVkT2ZmKHtqb2JJZCwgd29ya2VySWR9KSB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpXG5cbiAgICBjb25zdCBoYW5kZWRPZmZBdE1zID0gRGF0ZS5ub3coKVxuXG4gICAgYXdhaXQgdGhpcy5fd2l0aERiKGFzeW5jIChkYikgPT4ge1xuICAgICAgYXdhaXQgZGIudXBkYXRlKHtcbiAgICAgICAgdGFibGVOYW1lOiBKT0JTX1RBQkxFLFxuICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgc3RhdHVzOiBcImhhbmRlZF9vZmZcIixcbiAgICAgICAgICBoYW5kZWRfb2ZmX2F0X21zOiBoYW5kZWRPZmZBdE1zLFxuICAgICAgICAgIHdvcmtlcl9pZDogd29ya2VySWQgfHwgbnVsbFxuICAgICAgICB9LFxuICAgICAgICBjb25kaXRpb25zOiB7aWQ6IGpvYklkfVxuICAgICAgfSlcbiAgICB9KVxuXG4gICAgcmV0dXJuIGhhbmRlZE9mZkF0TXNcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmpvYklkIC0gSm9iIGlkLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3Mud29ya2VySWRdIC0gV29ya2VyIGlkLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3MuaGFuZGVkT2ZmQXRNc10gLSBIYW5kZWQgb2ZmIHRpbWVzdGFtcC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiB1cGRhdGVkLlxuICAgKi9cbiAgYXN5bmMgbWFya0NvbXBsZXRlZCh7am9iSWQsIHdvcmtlcklkLCBoYW5kZWRPZmZBdE1zfSkge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKVxuXG4gICAgYXdhaXQgdGhpcy5fd2l0aERiKGFzeW5jIChkYikgPT4ge1xuICAgICAgY29uc3Qgam9iID0gYXdhaXQgdGhpcy5fZ2V0Sm9iUm93QnlJZChkYiwgam9iSWQpXG5cbiAgICAgIGlmICgham9iKSByZXR1cm5cbiAgICAgIGlmICghdGhpcy5fc2hvdWxkQWNjZXB0UmVwb3J0KHtqb2IsIHdvcmtlcklkLCBoYW5kZWRPZmZBdE1zfSkpIHJldHVyblxuXG4gICAgICBhd2FpdCBkYi51cGRhdGUoe1xuICAgICAgICB0YWJsZU5hbWU6IEpPQlNfVEFCTEUsXG4gICAgICAgIGRhdGE6IHtcbiAgICAgICAgICBzdGF0dXM6IFwiY29tcGxldGVkXCIsXG4gICAgICAgICAgY29tcGxldGVkX2F0X21zOiBEYXRlLm5vdygpXG4gICAgICAgIH0sXG4gICAgICAgIGNvbmRpdGlvbnM6IHtpZDogam9iSWR9XG4gICAgICB9KVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy5qb2JJZCAtIEpvYiBpZC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiB1cGRhdGVkLlxuICAgKi9cbiAgYXN5bmMgbWFya1JldHVybmVkVG9RdWV1ZSh7am9iSWR9KSB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpXG5cbiAgICBhd2FpdCB0aGlzLl93aXRoRGIoYXN5bmMgKGRiKSA9PiB7XG4gICAgICBhd2FpdCBkYi51cGRhdGUoe1xuICAgICAgICB0YWJsZU5hbWU6IEpPQlNfVEFCTEUsXG4gICAgICAgIGRhdGE6IHtcbiAgICAgICAgICBzdGF0dXM6IFwicXVldWVkXCIsXG4gICAgICAgICAgc2NoZWR1bGVkX2F0X21zOiBEYXRlLm5vdygpLFxuICAgICAgICAgIGhhbmRlZF9vZmZfYXRfbXM6IG51bGwsXG4gICAgICAgICAgd29ya2VyX2lkOiBudWxsXG4gICAgICAgIH0sXG4gICAgICAgIGNvbmRpdGlvbnM6IHtpZDogam9iSWR9XG4gICAgICB9KVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy5qb2JJZCAtIEpvYiBpZC5cbiAgICogQHBhcmFtIHt1bmtub3dufSBhcmdzLmVycm9yIC0gRXJyb3IuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy53b3JrZXJJZF0gLSBXb3JrZXIgaWQuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy5oYW5kZWRPZmZBdE1zXSAtIEhhbmRlZCBvZmYgdGltZXN0YW1wLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIHVwZGF0ZWQuXG4gICAqL1xuICBhc3luYyBtYXJrRmFpbGVkKHtqb2JJZCwgZXJyb3IsIHdvcmtlcklkLCBoYW5kZWRPZmZBdE1zfSkge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKVxuXG4gICAgYXdhaXQgdGhpcy5fd2l0aERiKGFzeW5jIChkYikgPT4ge1xuICAgICAgY29uc3Qgam9iID0gYXdhaXQgdGhpcy5fZ2V0Sm9iUm93QnlJZChkYiwgam9iSWQpXG5cbiAgICAgIGlmICgham9iKSByZXR1cm5cbiAgICAgIGlmICghdGhpcy5fc2hvdWxkQWNjZXB0UmVwb3J0KHtqb2IsIHdvcmtlcklkLCBoYW5kZWRPZmZBdE1zfSkpIHJldHVyblxuXG4gICAgICBhd2FpdCB0aGlzLl9hcHBseUZhaWx1cmUoe2RiLCBqb2IsIGVycm9yLCBtYXJrT3JwaGFuZWQ6IGZhbHNlfSlcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBbYXJnc10gLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3Mub3JwaGFuZWRBZnRlck1zXSAtIE1hcmsgam9icyBvcnBoYW5lZCBhZnRlciB0aGlzIGR1cmF0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxudW1iZXI+fSAtIENvdW50IG9mIG9ycGhhbmVkIGpvYnMuXG4gICAqL1xuICBhc3luYyBtYXJrT3JwaGFuZWRKb2JzKHtvcnBoYW5lZEFmdGVyTXMgPSBPUlBIQU5FRF9BRlRFUl9NU30gPSB7fSkge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKVxuXG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuX3dpdGhEYihhc3luYyAoZGIpID0+IHtcbiAgICAgIGNvbnN0IGN1dG9mZiA9IERhdGUubm93KCkgLSBvcnBoYW5lZEFmdGVyTXNcbiAgICAgIGNvbnN0IHF1ZXJ5ID0gZGJcbiAgICAgICAgLm5ld1F1ZXJ5KClcbiAgICAgICAgLmZyb20oSk9CU19UQUJMRSlcbiAgICAgICAgLndoZXJlKHtzdGF0dXM6IFwiaGFuZGVkX29mZlwifSlcbiAgICAgICAgLndoZXJlKGBoYW5kZWRfb2ZmX2F0X21zIDw9ICR7ZGIucXVvdGUoY3V0b2ZmKX1gKVxuXG4gICAgICBjb25zdCByb3dzID0gYXdhaXQgcXVlcnkucmVzdWx0cygpXG5cbiAgICAgIGZvciAoY29uc3Qgcm93IG9mIHJvd3MpIHtcbiAgICAgICAgY29uc3Qgam9iID0gdGhpcy5fbm9ybWFsaXplSm9iUm93KHJvdylcblxuICAgICAgICBhd2FpdCB0aGlzLl9hcHBseUZhaWx1cmUoe1xuICAgICAgICAgIGRiLFxuICAgICAgICAgIGpvYixcbiAgICAgICAgICBlcnJvcjogXCJKb2Igb3JwaGFuZWQgYWZ0ZXIgdGltZW91dFwiLFxuICAgICAgICAgIG1hcmtPcnBoYW5lZDogdHJ1ZVxuICAgICAgICB9KVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gcm93cy5sZW5ndGhcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY2xlYXJlZC5cbiAgICovXG4gIGFzeW5jIGNsZWFyQWxsKCkge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKVxuXG4gICAgYXdhaXQgdGhpcy5fd2l0aERiKGFzeW5jIChkYikgPT4ge1xuICAgICAgYXdhaXQgZGIucXVlcnkoYERFTEVURSBGUk9NICR7ZGIucXVvdGVUYWJsZShKT0JTX1RBQkxFKX1gKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtudW1iZXJ9IHJldHJ5Q291bnQgLSBSZXRyeSBhdHRlbXB0IGNvdW50ICgxLWJhc2VkKS5cbiAgICogQHJldHVybnMge251bWJlcn0gLSBEZWxheSBpbiBtaWxsaXNlY29uZHMuXG4gICAqL1xuICBnZXRSZXRyeURlbGF5TXMocmV0cnlDb3VudCkge1xuICAgIGNvbnN0IHNjaGVkdWxlU2Vjb25kcyA9IFsxMCwgNjAsIDYwMCwgMzYwMF1cblxuICAgIGlmIChyZXRyeUNvdW50IDw9IHNjaGVkdWxlU2Vjb25kcy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiBzY2hlZHVsZVNlY29uZHNbcmV0cnlDb3VudCAtIDFdICogMTAwMFxuICAgIH1cblxuICAgIHJldHVybiAocmV0cnlDb3VudCAtIDMpICogNjAgKiA2MCAqIDEwMDBcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlciB8IHVuZGVmaW5lZH0gbWF4UmV0cmllcyAtIElucHV0LlxuICAgKiBAcmV0dXJucyB7bnVtYmVyfSAtIE5vcm1hbGl6ZWQgbWF4IHJldHJpZXMuXG4gICAqL1xuICBfbm9ybWFsaXplTWF4UmV0cmllcyhtYXhSZXRyaWVzKSB7XG4gICAgaWYgKHR5cGVvZiBtYXhSZXRyaWVzID09PSBcIm51bWJlclwiICYmIE51bWJlci5pc0Zpbml0ZShtYXhSZXRyaWVzKSAmJiBtYXhSZXRyaWVzID49IDApIHtcbiAgICAgIHJldHVybiBNYXRoLmZsb29yKG1heFJldHJpZXMpXG4gICAgfVxuXG4gICAgcmV0dXJuIERFRkFVTFRfTUFYX1JFVFJJRVNcbiAgfVxuXG4gIGFzeW5jIF9lbnN1cmVTY2hlbWEoKSB7XG4gICAgYXdhaXQgdGhpcy5fd2l0aERiKGFzeW5jIChkYikgPT4ge1xuICAgICAgYXdhaXQgdGhpcy5fZW5zdXJlTWlncmF0aW9uc1RhYmxlKGRiKVxuXG4gICAgICBjb25zdCBhbHJlYWR5QXBwbGllZCA9IGF3YWl0IHRoaXMuX2hhc01pZ3JhdGlvbihkYilcblxuICAgICAgaWYgKGFscmVhZHlBcHBsaWVkKSByZXR1cm5cblxuICAgICAgYXdhaXQgdGhpcy5fYXBwbHlNaWdyYXRpb25zKGRiKVxuICAgICAgYXdhaXQgZGIuaW5zZXJ0KHtcbiAgICAgICAgdGFibGVOYW1lOiBNSUdSQVRJT05TX1RBQkxFLFxuICAgICAgICBkYXRhOiB7XG4gICAgICAgICAga2V5OiB0aGlzLl9taWdyYXRpb25LZXkoKSxcbiAgICAgICAgICBzY29wZTogTUlHUkFUSU9OX1NDT1BFLFxuICAgICAgICAgIHZlcnNpb246IE1JR1JBVElPTl9WRVJTSU9OLFxuICAgICAgICAgIGFwcGxpZWRfYXRfbXM6IERhdGUubm93KClcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgYXN5bmMgX2Vuc3VyZU1pZ3JhdGlvbnNUYWJsZShkYikge1xuICAgIGlmIChhd2FpdCBkYi50YWJsZUV4aXN0cyhNSUdSQVRJT05TX1RBQkxFKSkgcmV0dXJuXG5cbiAgICBjb25zdCB0YWJsZSA9IG5ldyBUYWJsZURhdGEoTUlHUkFUSU9OU19UQUJMRSwge2lmTm90RXhpc3RzOiB0cnVlfSlcblxuICAgIHRhYmxlLnN0cmluZyhcImtleVwiLCB7bnVsbDogZmFsc2UsIHByaW1hcnlLZXk6IHRydWV9KVxuICAgIHRhYmxlLnN0cmluZyhcInNjb3BlXCIsIHtudWxsOiBmYWxzZX0pXG4gICAgdGFibGUuc3RyaW5nKFwidmVyc2lvblwiLCB7bnVsbDogZmFsc2V9KVxuICAgIHRhYmxlLmJpZ2ludChcImFwcGxpZWRfYXRfbXNcIiwge251bGw6IGZhbHNlfSlcblxuICAgIGF3YWl0IGRiLmNyZWF0ZVRhYmxlKHRhYmxlKVxuICB9XG5cbiAgYXN5bmMgX2hhc01pZ3JhdGlvbihkYikge1xuICAgIGNvbnN0IHF1ZXJ5ID0gZGJcbiAgICAgIC5uZXdRdWVyeSgpXG4gICAgICAuZnJvbShNSUdSQVRJT05TX1RBQkxFKVxuICAgICAgLndoZXJlKHtrZXk6IHRoaXMuX21pZ3JhdGlvbktleSgpfSlcbiAgICAgIC5saW1pdCgxKVxuXG4gICAgY29uc3Qgcm93cyA9IGF3YWl0IHF1ZXJ5LnJlc3VsdHMoKVxuXG4gICAgcmV0dXJuIHJvd3MubGVuZ3RoID4gMFxuICB9XG5cbiAgYXN5bmMgX2FwcGx5TWlncmF0aW9ucyhkYikge1xuICAgIHRoaXMubG9nZ2VyLmluZm8oXCJBcHBseWluZyBiYWNrZ3JvdW5kIGpvYnMgc2NoZW1hXCIpXG5cbiAgICBpZiAoYXdhaXQgZGIudGFibGVFeGlzdHMoSk9CU19UQUJMRSkpIHtcbiAgICAgIHRoaXMubG9nZ2VyLmluZm8oXCJCYWNrZ3JvdW5kIGpvYnMgdGFibGUgYWxyZWFkeSBleGlzdHMgLSBza2lwcGluZyBjcmVhdGVcIilcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGNvbnN0IHRhYmxlID0gbmV3IFRhYmxlRGF0YShKT0JTX1RBQkxFLCB7aWZOb3RFeGlzdHM6IHRydWV9KVxuXG4gICAgdGFibGUuc3RyaW5nKFwiaWRcIiwge3ByaW1hcnlLZXk6IHRydWV9KVxuICAgIHRhYmxlLnN0cmluZyhcImpvYl9uYW1lXCIsIHtudWxsOiBmYWxzZSwgaW5kZXg6IHRydWV9KVxuICAgIHRhYmxlLnRleHQoXCJhcmdzX2pzb25cIiwge251bGw6IGZhbHNlfSlcbiAgICB0YWJsZS5ib29sZWFuKFwiZm9ya2VkXCIsIHtudWxsOiBmYWxzZX0pXG4gICAgdGFibGUuaW50ZWdlcihcIm1heF9yZXRyaWVzXCIsIHtudWxsOiBmYWxzZX0pXG4gICAgdGFibGUuaW50ZWdlcihcImF0dGVtcHRzXCIsIHtudWxsOiBmYWxzZX0pXG4gICAgdGFibGUuc3RyaW5nKFwic3RhdHVzXCIsIHtudWxsOiBmYWxzZSwgaW5kZXg6IHRydWV9KVxuICAgIHRhYmxlLmJpZ2ludChcInNjaGVkdWxlZF9hdF9tc1wiLCB7bnVsbDogZmFsc2UsIGluZGV4OiB0cnVlfSlcbiAgICB0YWJsZS5iaWdpbnQoXCJjcmVhdGVkX2F0X21zXCIsIHtudWxsOiBmYWxzZSwgaW5kZXg6IHRydWV9KVxuICAgIHRhYmxlLmJpZ2ludChcImhhbmRlZF9vZmZfYXRfbXNcIiwge251bGw6IHRydWUsIGluZGV4OiB0cnVlfSlcbiAgICB0YWJsZS5iaWdpbnQoXCJjb21wbGV0ZWRfYXRfbXNcIiwge251bGw6IHRydWV9KVxuICAgIHRhYmxlLmJpZ2ludChcImZhaWxlZF9hdF9tc1wiLCB7bnVsbDogdHJ1ZX0pXG4gICAgdGFibGUuYmlnaW50KFwib3JwaGFuZWRfYXRfbXNcIiwge251bGw6IHRydWUsIGluZGV4OiB0cnVlfSlcbiAgICB0YWJsZS5zdHJpbmcoXCJ3b3JrZXJfaWRcIiwge251bGw6IHRydWV9KVxuICAgIHRhYmxlLnRleHQoXCJsYXN0X2Vycm9yXCIsIHtudWxsOiB0cnVlfSlcblxuICAgIGF3YWl0IGRiLmNyZWF0ZVRhYmxlKHRhYmxlKVxuICB9XG5cbiAgYXN5bmMgX2luaXRpYWxpemVNb2RlbCgpIHtcbiAgICBCYWNrZ3JvdW5kSm9iUmVjb3JkLnNldERhdGFiYXNlSWRlbnRpZmllcih0aGlzLmdldERhdGFiYXNlSWRlbnRpZmllcigpKVxuXG4gICAgaWYgKEJhY2tncm91bmRKb2JSZWNvcmQuaXNJbml0aWFsaXplZCgpKSByZXR1cm5cblxuICAgIGNvbnN0IHBvb2wgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0RGF0YWJhc2VQb29sKHRoaXMuZ2V0RGF0YWJhc2VJZGVudGlmaWVyKCkpXG5cbiAgICBhd2FpdCBwb29sLndpdGhDb25uZWN0aW9uKGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IEJhY2tncm91bmRKb2JSZWNvcmQuaW5pdGlhbGl6ZVJlY29yZCh7Y29uZmlndXJhdGlvbjogdGhpcy5jb25maWd1cmF0aW9ufSlcbiAgICB9KVxuICB9XG5cbiAgYXN5bmMgX2dldEpvYlJvd0J5SWQoZGIsIGpvYklkKSB7XG4gICAgY29uc3QgcXVlcnkgPSBkYlxuICAgICAgLm5ld1F1ZXJ5KClcbiAgICAgIC5mcm9tKEpPQlNfVEFCTEUpXG4gICAgICAud2hlcmUoe2lkOiBqb2JJZH0pXG4gICAgICAubGltaXQoMSlcblxuICAgIGNvbnN0IHJvd3MgPSBhd2FpdCBxdWVyeS5yZXN1bHRzKClcblxuICAgIGlmICghcm93c1swXSkgcmV0dXJuIG51bGxcblxuICAgIHJldHVybiB0aGlzLl9ub3JtYWxpemVKb2JSb3cocm93c1swXSlcbiAgfVxuXG4gIGFzeW5jIF9hcHBseUZhaWx1cmUoe2RiLCBqb2IsIGVycm9yLCBtYXJrT3JwaGFuZWR9KSB7XG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKVxuICAgIGNvbnN0IG5leHRBdHRlbXB0ID0gKGpvYi5hdHRlbXB0cyB8fCAwKSArIDFcbiAgICBjb25zdCBtYXhSZXRyaWVzID0gdGhpcy5fbm9ybWFsaXplTWF4UmV0cmllcyhqb2IubWF4UmV0cmllcylcbiAgICBjb25zdCBzaG91bGRSZXRyeSA9IG5leHRBdHRlbXB0IDw9IG1heFJldHJpZXNcbiAgICBjb25zdCBmYWlsdXJlTWVzc2FnZSA9IHRoaXMuX25vcm1hbGl6ZUVycm9yKGVycm9yKVxuICAgIGNvbnN0IHNjaGVkdWxlZEF0ID0gc2hvdWxkUmV0cnkgPyBub3cgKyB0aGlzLmdldFJldHJ5RGVsYXlNcyhuZXh0QXR0ZW1wdCkgOiBqb2Iuc2NoZWR1bGVkQXRNc1xuXG4gICAgLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSAqL1xuICAgIGNvbnN0IHVwZGF0ZSA9IHtcbiAgICAgIGF0dGVtcHRzOiBuZXh0QXR0ZW1wdCxcbiAgICAgIGhhbmRlZF9vZmZfYXRfbXM6IG51bGwsXG4gICAgICB3b3JrZXJfaWQ6IG51bGwsXG4gICAgICBsYXN0X2Vycm9yOiBmYWlsdXJlTWVzc2FnZVxuICAgIH1cblxuICAgIGlmIChtYXJrT3JwaGFuZWQpIHtcbiAgICAgIHVwZGF0ZS5vcnBoYW5lZF9hdF9tcyA9IG5vd1xuICAgIH1cblxuICAgIGlmIChzaG91bGRSZXRyeSkge1xuICAgICAgdXBkYXRlLnN0YXR1cyA9IFwicXVldWVkXCJcbiAgICAgIHVwZGF0ZS5zY2hlZHVsZWRfYXRfbXMgPSBzY2hlZHVsZWRBdFxuICAgIH0gZWxzZSBpZiAobWFya09ycGhhbmVkKSB7XG4gICAgICB1cGRhdGUuc3RhdHVzID0gXCJvcnBoYW5lZFwiXG4gICAgfSBlbHNlIHtcbiAgICAgIHVwZGF0ZS5zdGF0dXMgPSBcImZhaWxlZFwiXG4gICAgICB1cGRhdGUuZmFpbGVkX2F0X21zID0gbm93XG4gICAgfVxuXG4gICAgYXdhaXQgZGIudXBkYXRlKHtcbiAgICAgIHRhYmxlTmFtZTogSk9CU19UQUJMRSxcbiAgICAgIGRhdGE6IHVwZGF0ZSxcbiAgICAgIGNvbmRpdGlvbnM6IHtpZDogam9iLmlkfVxuICAgIH0pXG4gIH1cblxuICBfbm9ybWFsaXplSm9iUm93KHJvdykge1xuICAgIHJldHVybiB7XG4gICAgICBpZDogU3RyaW5nKHJvdy5pZCksXG4gICAgICBqb2JOYW1lOiBTdHJpbmcocm93LmpvYl9uYW1lKSxcbiAgICAgIGFyZ3M6IHRoaXMuX3BhcnNlQXJncyhyb3cuYXJnc19qc29uKSxcbiAgICAgIGZvcmtlZDogdGhpcy5fbm9ybWFsaXplQm9vbGVhbihyb3cuZm9ya2VkKSxcbiAgICAgIHN0YXR1czogcm93LnN0YXR1cyA/IFN0cmluZyhyb3cuc3RhdHVzKSA6IFwicXVldWVkXCIsXG4gICAgICBhdHRlbXB0czogdGhpcy5fbm9ybWFsaXplTnVtYmVyKHJvdy5hdHRlbXB0cyksXG4gICAgICBtYXhSZXRyaWVzOiB0aGlzLl9ub3JtYWxpemVOdW1iZXIocm93Lm1heF9yZXRyaWVzKSxcbiAgICAgIHNjaGVkdWxlZEF0TXM6IHRoaXMuX25vcm1hbGl6ZU51bWJlcihyb3cuc2NoZWR1bGVkX2F0X21zKSxcbiAgICAgIGNyZWF0ZWRBdE1zOiB0aGlzLl9ub3JtYWxpemVOdW1iZXIocm93LmNyZWF0ZWRfYXRfbXMpLFxuICAgICAgaGFuZGVkT2ZmQXRNczogdGhpcy5fbm9ybWFsaXplTnVtYmVyKHJvdy5oYW5kZWRfb2ZmX2F0X21zKSxcbiAgICAgIGNvbXBsZXRlZEF0TXM6IHRoaXMuX25vcm1hbGl6ZU51bWJlcihyb3cuY29tcGxldGVkX2F0X21zKSxcbiAgICAgIGZhaWxlZEF0TXM6IHRoaXMuX25vcm1hbGl6ZU51bWJlcihyb3cuZmFpbGVkX2F0X21zKSxcbiAgICAgIG9ycGhhbmVkQXRNczogdGhpcy5fbm9ybWFsaXplTnVtYmVyKHJvdy5vcnBoYW5lZF9hdF9tcyksXG4gICAgICB3b3JrZXJJZDogcm93Lndvcmtlcl9pZCA/IFN0cmluZyhyb3cud29ya2VyX2lkKSA6IG51bGwsXG4gICAgICBsYXN0RXJyb3I6IHJvdy5sYXN0X2Vycm9yID8gU3RyaW5nKHJvdy5sYXN0X2Vycm9yKSA6IG51bGxcbiAgICB9XG4gIH1cblxuICBfbm9ybWFsaXplTnVtYmVyKHZhbHVlKSB7XG4gICAgaWYgKHZhbHVlID09PSBudWxsIHx8IHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IFwiXCIpIHJldHVybiBudWxsXG5cbiAgICBjb25zdCBudW1lcmljID0gTnVtYmVyKHZhbHVlKVxuXG4gICAgaWYgKE51bWJlci5pc05hTihudW1lcmljKSkgcmV0dXJuIG51bGxcblxuICAgIHJldHVybiBudW1lcmljXG4gIH1cblxuICBfbm9ybWFsaXplQm9vbGVhbih2YWx1ZSkge1xuICAgIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gZmFsc2VcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcImJvb2xlYW5cIikgcmV0dXJuIHZhbHVlXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJudW1iZXJcIikgcmV0dXJuIHZhbHVlICE9PSAwXG5cbiAgICByZXR1cm4gdmFsdWUgPT09IFwidHJ1ZVwiXG4gIH1cblxuICBfcGFyc2VBcmdzKHZhbHVlKSB7XG4gICAgaWYgKCF2YWx1ZSkgcmV0dXJuIFtdXG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcGFyc2VkID0gSlNPTi5wYXJzZShTdHJpbmcodmFsdWUpKVxuXG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShwYXJzZWQpKSByZXR1cm4gcGFyc2VkXG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBJZ25vcmUgcGFyc2UgZXJyb3JzLlxuICAgIH1cblxuICAgIHJldHVybiBbXVxuICB9XG5cbiAgX25vcm1hbGl6ZUVycm9yKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHJldHVybiBlcnJvci5zdGFjayB8fCBlcnJvci5tZXNzYWdlXG4gICAgaWYgKHR5cGVvZiBlcnJvciA9PT0gXCJzdHJpbmdcIikgcmV0dXJuIGVycm9yXG5cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGVycm9yKVxuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIFN0cmluZyhlcnJvcilcbiAgICB9XG4gIH1cblxuICBhc3luYyBfd2l0aERiKGNhbGxiYWNrKSB7XG4gICAgY29uc3QgcG9vbCA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXREYXRhYmFzZVBvb2wodGhpcy5nZXREYXRhYmFzZUlkZW50aWZpZXIoKSlcbiAgICBsZXQgcmVzdWx0XG5cbiAgICBhd2FpdCBwb29sLndpdGhDb25uZWN0aW9uKGFzeW5jIChkYikgPT4ge1xuICAgICAgcmVzdWx0ID0gYXdhaXQgY2FsbGJhY2soZGIpXG4gICAgfSlcblxuICAgIHJldHVybiByZXN1bHRcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9zdG9yZS5qc1wiKS5CYWNrZ3JvdW5kSm9iUm93fSBhcmdzLmpvYiAtIEpvYiByb3cuXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZH0gYXJncy53b3JrZXJJZCAtIFdvcmtlciBpZCBmcm9tIHJlcG9ydC5cbiAgICogQHBhcmFtIHtudW1iZXIgfCBudWxsIHwgdW5kZWZpbmVkfSBhcmdzLmhhbmRlZE9mZkF0TXMgLSBIYW5kZWQgb2ZmIHRpbWVzdGFtcCBmcm9tIHJlcG9ydC5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gV2hldGhlciB0byBhY2NlcHQgdGhlIHJlcG9ydC5cbiAgICovXG4gIF9zaG91bGRBY2NlcHRSZXBvcnQoe2pvYiwgd29ya2VySWQsIGhhbmRlZE9mZkF0TXN9KSB7XG4gICAgaWYgKGpvYi5zdGF0dXMgIT09IFwiaGFuZGVkX29mZlwiKSByZXR1cm4gZmFsc2VcblxuICAgIGlmICh3b3JrZXJJZCAmJiBqb2Iud29ya2VySWQgJiYgd29ya2VySWQgIT09IGpvYi53b3JrZXJJZCkgcmV0dXJuIGZhbHNlXG5cbiAgICBpZiAoaGFuZGVkT2ZmQXRNcyAmJiBqb2IuaGFuZGVkT2ZmQXRNcyAmJiBoYW5kZWRPZmZBdE1zICE9PSBqb2IuaGFuZGVkT2ZmQXRNcykgcmV0dXJuIGZhbHNlXG5cbiAgICByZXR1cm4gdHJ1ZVxuICB9XG5cbiAgX21pZ3JhdGlvbktleSgpIHtcbiAgICByZXR1cm4gYCR7TUlHUkFUSU9OX1NDT1BFfToke01JR1JBVElPTl9WRVJTSU9OfWBcbiAgfVxufVxuXG4vKipcbiAqIEB0eXBlZGVmIHtvYmplY3R9IEJhY2tncm91bmRKb2JSb3dcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBpZCAtIEpvYiBpZC5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBqb2JOYW1lIC0gSm9iIGNsYXNzIG5hbWUuXG4gKiBAcHJvcGVydHkge2FueVtdfSBhcmdzIC0gU2VyaWFsaXplZCBqb2IgYXJndW1lbnRzLlxuICogQHByb3BlcnR5IHtib29sZWFufSBmb3JrZWQgLSBXaGV0aGVyIHRoZSBqb2IgaXMgZm9ya2VkLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IHN0YXR1cyAtIEN1cnJlbnQgam9iIHN0YXR1cy5cbiAqIEBwcm9wZXJ0eSB7bnVtYmVyIHwgbnVsbH0gYXR0ZW1wdHMgLSBGYWlsdXJlIGF0dGVtcHRzIGNvdW50LlxuICogQHByb3BlcnR5IHtudW1iZXIgfCBudWxsfSBtYXhSZXRyaWVzIC0gTWF4IHJldHJ5IGF0dGVtcHRzLlxuICogQHByb3BlcnR5IHtudW1iZXIgfCBudWxsfSBzY2hlZHVsZWRBdE1zIC0gTmV4dCBzY2hlZHVsZWQgdGltZSBpbiBtcy5cbiAqIEBwcm9wZXJ0eSB7bnVtYmVyIHwgbnVsbH0gY3JlYXRlZEF0TXMgLSBDcmVhdGlvbiB0aW1lIGluIG1zLlxuICogQHByb3BlcnR5IHtudW1iZXIgfCBudWxsfSBoYW5kZWRPZmZBdE1zIC0gVGltZSBoYW5kZWQgdG8gd29ya2VyIGluIG1zLlxuICogQHByb3BlcnR5IHtudW1iZXIgfCBudWxsfSBjb21wbGV0ZWRBdE1zIC0gQ29tcGxldGlvbiB0aW1lIGluIG1zLlxuICogQHByb3BlcnR5IHtudW1iZXIgfCBudWxsfSBmYWlsZWRBdE1zIC0gRmFpbHVyZSB0aW1lIGluIG1zLlxuICogQHByb3BlcnR5IHtudW1iZXIgfCBudWxsfSBvcnBoYW5lZEF0TXMgLSBPcnBoYW5lZCB0aW1lIGluIG1zLlxuICogQHByb3BlcnR5IHtzdHJpbmcgfCBudWxsfSB3b3JrZXJJZCAtIFdvcmtlciBpZCBoYW5kbGluZyB0aGUgam9iLlxuICogQHByb3BlcnR5IHtzdHJpbmcgfCBudWxsfSBsYXN0RXJyb3IgLSBMYXN0IGZhaWx1cmUgbWVzc2FnZS5cbiAqL1xuIl19
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} BackgroundJobOptions
|
|
3
|
+
* @property {boolean} [forked] - Whether the job should run forked. Defaults to true.
|
|
4
|
+
* @property {number} [maxRetries] - Max retries for a failed job before it is marked failed.
|
|
5
|
+
*/
|
|
6
|
+
export const nothing: {};
|
|
7
|
+
export type BackgroundJobOptions = {
|
|
8
|
+
/**
|
|
9
|
+
* - Whether the job should run forked. Defaults to true.
|
|
10
|
+
*/
|
|
11
|
+
forked?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* - Max retries for a failed job before it is marked failed.
|
|
14
|
+
*/
|
|
15
|
+
maxRetries?: number;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/types.js"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,yBAAyB;;;;;aAJX,OAAO;;;;iBACP,MAAM"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* @typedef {object} BackgroundJobOptions
|
|
4
|
+
* @property {boolean} [forked] - Whether the job should run forked. Defaults to true.
|
|
5
|
+
* @property {number} [maxRetries] - Max retries for a failed job before it is marked failed.
|
|
6
|
+
*/
|
|
7
|
+
export const nothing = {};
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYmFja2dyb3VuZC1qb2JzL3R5cGVzLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWjs7OztHQUlHO0FBRUgsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUFHLEVBQUUsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG4vKipcbiAqIEB0eXBlZGVmIHtvYmplY3R9IEJhY2tncm91bmRKb2JPcHRpb25zXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IFtmb3JrZWRdIC0gV2hldGhlciB0aGUgam9iIHNob3VsZCBydW4gZm9ya2VkLiBEZWZhdWx0cyB0byB0cnVlLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IFttYXhSZXRyaWVzXSAtIE1heCByZXRyaWVzIGZvciBhIGZhaWxlZCBqb2IgYmVmb3JlIGl0IGlzIG1hcmtlZCBmYWlsZWQuXG4gKi9cblxuZXhwb3J0IGNvbnN0IG5vdGhpbmcgPSB7fVxuIl19
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export default class BackgroundJobsWorker {
|
|
2
|
+
/**
|
|
3
|
+
* @param {object} [args] - Options.
|
|
4
|
+
* @param {import("../configuration.js").default} [args.configuration] - Configuration.
|
|
5
|
+
* @param {string} [args.host] - Hostname.
|
|
6
|
+
* @param {number} [args.port] - Port.
|
|
7
|
+
*/
|
|
8
|
+
constructor({ configuration, host, port }?: {
|
|
9
|
+
configuration?: import("../configuration.js").default;
|
|
10
|
+
host?: string;
|
|
11
|
+
port?: number;
|
|
12
|
+
});
|
|
13
|
+
configurationPromise: Promise<import("../configuration.js").default>;
|
|
14
|
+
host: string;
|
|
15
|
+
port: number;
|
|
16
|
+
shouldStop: boolean;
|
|
17
|
+
workerId: `${string}-${string}-${string}-${string}-${string}`;
|
|
18
|
+
/**
|
|
19
|
+
* @returns {Promise<void>} - Resolves when connected.
|
|
20
|
+
*/
|
|
21
|
+
start(): Promise<void>;
|
|
22
|
+
configuration: import("../configuration.js").default;
|
|
23
|
+
statusReporter: BackgroundJobsStatusReporter;
|
|
24
|
+
/**
|
|
25
|
+
* @returns {Promise<void>} - Resolves when stopped.
|
|
26
|
+
*/
|
|
27
|
+
stop(): Promise<void>;
|
|
28
|
+
_connect(): Promise<void>;
|
|
29
|
+
jsonSocket: JsonSocket;
|
|
30
|
+
/**
|
|
31
|
+
* @param {object} payload - Payload.
|
|
32
|
+
* @returns {Promise<void>} - Resolves when done.
|
|
33
|
+
*/
|
|
34
|
+
_handleJob(payload: object): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* @param {object} payload - Payload.
|
|
37
|
+
* @returns {Promise<void>} - Resolves when done.
|
|
38
|
+
*/
|
|
39
|
+
_runJobInline(payload: object): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* @param {object} payload - Payload.
|
|
42
|
+
* @returns {Promise<void>} - Resolves when spawned.
|
|
43
|
+
*/
|
|
44
|
+
_spawnDetachedJob(payload: object): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* @param {object} args - Options.
|
|
47
|
+
* @param {string} args.jobId - Job id.
|
|
48
|
+
* @param {"completed" | "failed"} args.status - Status.
|
|
49
|
+
* @param {unknown} [args.error] - Error.
|
|
50
|
+
* @param {number} [args.handedOffAtMs] - Handed off timestamp.
|
|
51
|
+
* @param {string} [args.workerId] - Worker id.
|
|
52
|
+
* @returns {Promise<void>} - Resolves when reported.
|
|
53
|
+
*/
|
|
54
|
+
_reportJobResult({ jobId, status, error, handedOffAtMs, workerId }: {
|
|
55
|
+
jobId: string;
|
|
56
|
+
status: "completed" | "failed";
|
|
57
|
+
error?: unknown;
|
|
58
|
+
handedOffAtMs?: number;
|
|
59
|
+
workerId?: string;
|
|
60
|
+
}): Promise<void>;
|
|
61
|
+
}
|
|
62
|
+
import BackgroundJobsStatusReporter from "./status-reporter.js";
|
|
63
|
+
import JsonSocket from "./json-socket.js";
|
|
64
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/worker.js"],"names":[],"mappings":"AAUA;IACE;;;;;OAKG;IACH,4CAJG;QAAqD,aAAa,GAA1D,OAAO,qBAAqB,EAAE,OAAO;QACvB,IAAI,GAAlB,MAAM;QACQ,IAAI,GAAlB,MAAM;KAChB,EAOA;IALC,qEAAoG;IACpG,aAAgB;IAChB,aAAgB;IAChB,oBAAuB;IACvB,8DAA4B;IAG9B;;OAEG;IACH,SAFa,OAAO,CAAC,IAAI,CAAC,CAYzB;IATC,qDAAoD;IAGpD,6CAIE;IAIJ;;OAEG;IACH,QAFa,OAAO,CAAC,IAAI,CAAC,CAKzB;IAED,0BA2BC;IArBC,uBAA4B;IAuB9B;;;OAGG;IACH,oBAHW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CA8BzB;IAED;;;OAGG;IACH,uBAHW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CASzB;IAED;;;OAGG;IACH,2BAHW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAoBzB;IAED;;;;;;;;OAQG;IACH,oEAPG;QAAqB,KAAK,EAAlB,MAAM;QACuB,MAAM,EAAnC,WAAW,GAAG,QAAQ;QACP,KAAK,GAApB,OAAO;QACO,aAAa,GAA3B,MAAM;QACQ,QAAQ,GAAtB,MAAM;KACd,GAAU,OAAO,CAAC,IAAI,CAAC,CAUzB;CACF;yCA/JwC,sBAAsB;uBAHxC,kBAAkB"}
|