velocious 1.0.177 → 1.0.179

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.
Files changed (89) hide show
  1. package/README.md +125 -0
  2. package/build/src/background-jobs/client.d.ts +23 -0
  3. package/build/src/background-jobs/client.d.ts.map +1 -0
  4. package/build/src/background-jobs/client.js +58 -0
  5. package/build/src/background-jobs/job-record.d.ts +4 -0
  6. package/build/src/background-jobs/job-record.d.ts.map +1 -0
  7. package/build/src/background-jobs/job-record.js +11 -0
  8. package/build/src/background-jobs/job-registry.d.ts +23 -0
  9. package/build/src/background-jobs/job-registry.d.ts.map +1 -0
  10. package/build/src/background-jobs/job-registry.js +55 -0
  11. package/build/src/background-jobs/job-runner.d.ts +6 -0
  12. package/build/src/background-jobs/job-runner.d.ts.map +1 -0
  13. package/build/src/background-jobs/job-runner.js +44 -0
  14. package/build/src/background-jobs/job.d.ts +35 -0
  15. package/build/src/background-jobs/job.d.ts.map +1 -0
  16. package/build/src/background-jobs/job.js +61 -0
  17. package/build/src/background-jobs/json-socket.d.ts +27 -0
  18. package/build/src/background-jobs/json-socket.d.ts.map +1 -0
  19. package/build/src/background-jobs/json-socket.js +55 -0
  20. package/build/src/background-jobs/main.d.ts +62 -0
  21. package/build/src/background-jobs/main.d.ts.map +1 -0
  22. package/build/src/background-jobs/main.js +216 -0
  23. package/build/src/background-jobs/status-reporter.d.ts +54 -0
  24. package/build/src/background-jobs/status-reporter.d.ts.map +1 -0
  25. package/build/src/background-jobs/status-reporter.js +113 -0
  26. package/build/src/background-jobs/store.d.ts +237 -0
  27. package/build/src/background-jobs/store.d.ts.map +1 -0
  28. package/build/src/background-jobs/store.js +488 -0
  29. package/build/src/background-jobs/types.d.ts +17 -0
  30. package/build/src/background-jobs/types.d.ts.map +1 -0
  31. package/build/src/background-jobs/types.js +8 -0
  32. package/build/src/background-jobs/worker.d.ts +64 -0
  33. package/build/src/background-jobs/worker.d.ts.map +1 -0
  34. package/build/src/background-jobs/worker.js +155 -0
  35. package/build/src/cli/commands/background-jobs-main.d.ts +5 -0
  36. package/build/src/cli/commands/background-jobs-main.d.ts.map +1 -0
  37. package/build/src/cli/commands/background-jobs-main.js +7 -0
  38. package/build/src/cli/commands/background-jobs-runner.d.ts +5 -0
  39. package/build/src/cli/commands/background-jobs-runner.d.ts.map +1 -0
  40. package/build/src/cli/commands/background-jobs-runner.js +7 -0
  41. package/build/src/cli/commands/background-jobs-worker.d.ts +5 -0
  42. package/build/src/cli/commands/background-jobs-worker.d.ts.map +1 -0
  43. package/build/src/cli/commands/background-jobs-worker.js +7 -0
  44. package/build/src/configuration-types.d.ts +25 -0
  45. package/build/src/configuration-types.d.ts.map +1 -1
  46. package/build/src/configuration-types.js +8 -1
  47. package/build/src/configuration.d.ts +11 -1
  48. package/build/src/configuration.d.ts.map +1 -1
  49. package/build/src/configuration.js +26 -2
  50. package/build/src/database/drivers/mssql/sql/update.js +3 -3
  51. package/build/src/database/drivers/mysql/sql/update.js +3 -3
  52. package/build/src/database/drivers/pgsql/sql/update.js +3 -3
  53. package/build/src/database/drivers/sqlite/sql/update.js +3 -3
  54. package/build/src/database/query/update-base.d.ts +5 -0
  55. package/build/src/database/query/update-base.d.ts.map +1 -1
  56. package/build/src/database/query/update-base.js +10 -1
  57. package/build/src/database/query-parser/limit-parser.d.ts.map +1 -1
  58. package/build/src/database/query-parser/limit-parser.js +8 -7
  59. package/build/src/environment-handlers/base.d.ts +15 -0
  60. package/build/src/environment-handlers/base.d.ts.map +1 -1
  61. package/build/src/environment-handlers/base.js +22 -1
  62. package/build/src/environment-handlers/browser.d.ts.map +1 -1
  63. package/build/src/environment-handlers/browser.js +10 -1
  64. package/build/src/environment-handlers/node/cli/commands/background-jobs-main.d.ts +5 -0
  65. package/build/src/environment-handlers/node/cli/commands/background-jobs-main.d.ts.map +1 -0
  66. package/build/src/environment-handlers/node/cli/commands/background-jobs-main.js +18 -0
  67. package/build/src/environment-handlers/node/cli/commands/background-jobs-runner.d.ts +5 -0
  68. package/build/src/environment-handlers/node/cli/commands/background-jobs-runner.d.ts.map +1 -0
  69. package/build/src/environment-handlers/node/cli/commands/background-jobs-runner.js +13 -0
  70. package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.d.ts +5 -0
  71. package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.d.ts.map +1 -0
  72. package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.js +18 -0
  73. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
  74. package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +6 -4
  75. package/build/src/environment-handlers/node/cli/commands/test.d.ts.map +1 -1
  76. package/build/src/environment-handlers/node/cli/commands/test.js +2 -116
  77. package/build/src/environment-handlers/node.d.ts.map +1 -1
  78. package/build/src/environment-handlers/node.js +25 -1
  79. package/build/src/testing/browser-test-app.d.ts +2 -0
  80. package/build/src/testing/browser-test-app.d.ts.map +1 -0
  81. package/build/src/testing/browser-test-app.js +24 -0
  82. package/build/src/testing/test-filter-parser.d.ts +16 -0
  83. package/build/src/testing/test-filter-parser.d.ts.map +1 -0
  84. package/build/src/testing/test-filter-parser.js +117 -0
  85. package/build/src/testing/test-runner.d.ts +35 -0
  86. package/build/src/testing/test-runner.d.ts.map +1 -1
  87. package/build/src/testing/test-runner.js +100 -17
  88. package/build/tsconfig.tsbuildinfo +1 -1
  89. package/package.json +4 -1
@@ -0,0 +1,62 @@
1
+ export default class BackgroundJobsMain {
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
+ configuration: import("../configuration.js").default;
14
+ host: string;
15
+ port: number;
16
+ store: BackgroundJobsStore;
17
+ logger: Logger;
18
+ /** @type {Set<JsonSocket>} */
19
+ workers: Set<JsonSocket>;
20
+ /** @type {Set<JsonSocket>} */
21
+ readyWorkers: Set<JsonSocket>;
22
+ _dispatching: boolean;
23
+ /**
24
+ * @returns {Promise<void>} - Resolves when listening.
25
+ */
26
+ start(): Promise<void>;
27
+ server: net.Server;
28
+ _dispatchTimer: NodeJS.Timeout;
29
+ _orphanTimer: NodeJS.Timeout;
30
+ /**
31
+ * @returns {Promise<void>} - Resolves when closed.
32
+ */
33
+ stop(): Promise<void>;
34
+ /**
35
+ * @returns {number} - Bound port.
36
+ */
37
+ getPort(): number;
38
+ /**
39
+ * @param {import("net").Socket} socket - Socket.
40
+ * @returns {void}
41
+ */
42
+ _handleConnection(socket: import("net").Socket): void;
43
+ _handleEnqueue({ jsonSocket, message }: {
44
+ jsonSocket: any;
45
+ message: any;
46
+ }): Promise<void>;
47
+ _handleJobComplete({ jsonSocket, message }: {
48
+ jsonSocket: any;
49
+ message: any;
50
+ }): Promise<void>;
51
+ _handleJobFailed({ jsonSocket, message }: {
52
+ jsonSocket: any;
53
+ message: any;
54
+ }): Promise<void>;
55
+ _dispatch(): Promise<void>;
56
+ _sweepOrphans(): Promise<void>;
57
+ }
58
+ import BackgroundJobsStore from "./store.js";
59
+ import { Logger } from "../logger.js";
60
+ import JsonSocket from "./json-socket.js";
61
+ import net from "net";
62
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/main.js"],"names":[],"mappings":"AAOA;IACE;;;;;OAKG;IACH,2CAJG;QAAoD,aAAa,EAAzD,OAAO,qBAAqB,EAAE,OAAO;QACvB,IAAI,GAAlB,MAAM;QACQ,IAAI,GAAlB,MAAM;KAChB,EAaA;IAXC,qDAAkC;IAElC,aAA+B;IAC/B,aAAyD;IACzD,2BAAoG;IACpG,eAA8B;IAC9B,8BAA8B;IAC9B,SADW,GAAG,CAAC,UAAU,CAAC,CACF;IACxB,8BAA8B;IAC9B,cADW,GAAG,CAAC,UAAU,CAAC,CACG;IAC7B,sBAAyB;IAG3B;;OAEG;IACH,SAFa,OAAO,CAAC,IAAI,CAAC,CAyBzB;IAnBC,mBAA0E;IAY1E,+BAEQ;IAER,6BAES;IAGX;;OAEG;IACH,QAFa,OAAO,CAAC,IAAI,CAAC,CAazB;IAED;;OAEG;IACH,WAFa,MAAM,CAIlB;IAED;;;OAGG;IACH,0BAHW,OAAO,KAAK,EAAE,MAAM,GAClB,IAAI,CAqDhB;IAED;;;sBAcC;IAED;;;sBAYC;IAED;;;sBAcC;IAED,2BAyCC;IAED,+BAUC;CACF;gCAxO+B,YAAY;uBACvB,cAAc;uBAFZ,kBAAkB;gBADzB,KAAK"}
@@ -0,0 +1,216 @@
1
+ // @ts-check
2
+ import net from "net";
3
+ import JsonSocket from "./json-socket.js";
4
+ import BackgroundJobsStore from "./store.js";
5
+ import { Logger } from "../logger.js";
6
+ export default class BackgroundJobsMain {
7
+ /**
8
+ * @param {object} args - Options.
9
+ * @param {import("../configuration.js").default} args.configuration - Configuration.
10
+ * @param {string} [args.host] - Hostname.
11
+ * @param {number} [args.port] - Port.
12
+ */
13
+ constructor({ configuration, host, port }) {
14
+ this.configuration = configuration;
15
+ const config = configuration.getBackgroundJobsConfig();
16
+ this.host = host || config.host;
17
+ this.port = typeof port === "number" ? port : config.port;
18
+ this.store = new BackgroundJobsStore({ configuration, databaseIdentifier: config.databaseIdentifier });
19
+ this.logger = new Logger(this);
20
+ /** @type {Set<JsonSocket>} */
21
+ this.workers = new Set();
22
+ /** @type {Set<JsonSocket>} */
23
+ this.readyWorkers = new Set();
24
+ this._dispatching = false;
25
+ }
26
+ /**
27
+ * @returns {Promise<void>} - Resolves when listening.
28
+ */
29
+ async start() {
30
+ this.configuration.setCurrent();
31
+ await this.configuration.initialize({ type: "background-jobs-main" });
32
+ await this.store.ensureReady();
33
+ this.server = net.createServer((socket) => this._handleConnection(socket));
34
+ await new Promise((resolve, reject) => {
35
+ this.server.once("error", reject);
36
+ this.server.listen(this.port, this.host, () => resolve(undefined));
37
+ });
38
+ const address = this.server.address();
39
+ if (address && typeof address === "object") {
40
+ this.port = address.port;
41
+ }
42
+ this._dispatchTimer = setInterval(() => {
43
+ void this._dispatch();
44
+ }, 1000);
45
+ this._orphanTimer = setInterval(() => {
46
+ void this._sweepOrphans();
47
+ }, 60000);
48
+ }
49
+ /**
50
+ * @returns {Promise<void>} - Resolves when closed.
51
+ */
52
+ async stop() {
53
+ for (const worker of this.workers) {
54
+ worker.close();
55
+ }
56
+ if (this._dispatchTimer)
57
+ clearInterval(this._dispatchTimer);
58
+ if (this._orphanTimer)
59
+ clearInterval(this._orphanTimer);
60
+ if (!this.server)
61
+ return;
62
+ await new Promise((resolve) => this.server.close(() => resolve(undefined)));
63
+ }
64
+ /**
65
+ * @returns {number} - Bound port.
66
+ */
67
+ getPort() {
68
+ return this.port;
69
+ }
70
+ /**
71
+ * @param {import("net").Socket} socket - Socket.
72
+ * @returns {void}
73
+ */
74
+ _handleConnection(socket) {
75
+ const jsonSocket = new JsonSocket(socket);
76
+ let role = null;
77
+ const cleanup = () => {
78
+ if (role === "worker") {
79
+ this.workers.delete(jsonSocket);
80
+ this.readyWorkers.delete(jsonSocket);
81
+ }
82
+ };
83
+ jsonSocket.on("close", cleanup);
84
+ jsonSocket.on("error", (error) => {
85
+ this.logger.warn(() => ["Background jobs connection error:", error]);
86
+ cleanup();
87
+ });
88
+ jsonSocket.on("message", (message) => {
89
+ if (!role && message?.type === "hello") {
90
+ role = message.role;
91
+ if (role === "worker") {
92
+ jsonSocket.workerId = message.workerId;
93
+ this.workers.add(jsonSocket);
94
+ this.readyWorkers.add(jsonSocket);
95
+ this._dispatch();
96
+ }
97
+ return;
98
+ }
99
+ if (role === "client" && message?.type === "enqueue") {
100
+ this._handleEnqueue({ jsonSocket, message });
101
+ return;
102
+ }
103
+ if (role === "worker" && message?.type === "ready") {
104
+ this.readyWorkers.add(jsonSocket);
105
+ this._dispatch();
106
+ return;
107
+ }
108
+ if ((role === "worker" || role === "reporter") && message?.type === "job-complete") {
109
+ this._handleJobComplete({ jsonSocket, message });
110
+ return;
111
+ }
112
+ if ((role === "worker" || role === "reporter") && message?.type === "job-failed") {
113
+ this._handleJobFailed({ jsonSocket, message });
114
+ }
115
+ });
116
+ }
117
+ async _handleEnqueue({ jsonSocket, message }) {
118
+ try {
119
+ const jobId = await this.store.enqueue({
120
+ jobName: message.jobName,
121
+ args: message.args || [],
122
+ options: message.options || {}
123
+ });
124
+ jsonSocket.send({ type: "enqueued", jobId });
125
+ await this._dispatch();
126
+ }
127
+ catch (error) {
128
+ this.logger.error(() => ["Failed to enqueue background job:", error]);
129
+ jsonSocket.send({ type: "enqueue-error", error: "Failed to enqueue job" });
130
+ }
131
+ }
132
+ async _handleJobComplete({ jsonSocket, message }) {
133
+ try {
134
+ await this.store.markCompleted({
135
+ jobId: message.jobId,
136
+ workerId: message.workerId,
137
+ handedOffAtMs: message.handedOffAtMs
138
+ });
139
+ jsonSocket.send({ type: "job-updated", jobId: message.jobId });
140
+ }
141
+ catch (error) {
142
+ this.logger.error(() => ["Failed to update job completion:", error]);
143
+ jsonSocket.send({ type: "job-update-error", jobId: message.jobId, error: "Failed to update job" });
144
+ }
145
+ }
146
+ async _handleJobFailed({ jsonSocket, message }) {
147
+ try {
148
+ await this.store.markFailed({
149
+ jobId: message.jobId,
150
+ error: message.error,
151
+ workerId: message.workerId,
152
+ handedOffAtMs: message.handedOffAtMs
153
+ });
154
+ jsonSocket.send({ type: "job-updated", jobId: message.jobId });
155
+ await this._dispatch();
156
+ }
157
+ catch (error) {
158
+ this.logger.error(() => ["Failed to update job failure:", error]);
159
+ jsonSocket.send({ type: "job-update-error", jobId: message.jobId, error: "Failed to update job" });
160
+ }
161
+ }
162
+ async _dispatch() {
163
+ if (this._dispatching)
164
+ return;
165
+ if (this.readyWorkers.size === 0)
166
+ return;
167
+ this._dispatching = true;
168
+ try {
169
+ while (this.readyWorkers.size > 0) {
170
+ const job = await this.store.nextAvailableJob();
171
+ if (!job)
172
+ return;
173
+ const [worker] = this.readyWorkers;
174
+ if (!worker)
175
+ return;
176
+ this.readyWorkers.delete(worker);
177
+ const handedOffAtMs = await this.store.markHandedOff({ jobId: job.id, workerId: worker.workerId });
178
+ try {
179
+ worker.send({
180
+ type: "job",
181
+ payload: {
182
+ id: job.id,
183
+ jobName: job.jobName,
184
+ args: job.args,
185
+ workerId: worker.workerId,
186
+ handedOffAtMs,
187
+ options: {
188
+ forked: job.forked
189
+ }
190
+ }
191
+ });
192
+ }
193
+ catch (error) {
194
+ this.logger.warn(() => ["Failed to send job to worker, re-queueing:", error]);
195
+ await this.store.markReturnedToQueue({ jobId: job.id });
196
+ this.readyWorkers.add(worker);
197
+ }
198
+ }
199
+ }
200
+ finally {
201
+ this._dispatching = false;
202
+ }
203
+ }
204
+ async _sweepOrphans() {
205
+ try {
206
+ const count = await this.store.markOrphanedJobs();
207
+ if (count > 0) {
208
+ this.logger.warn(() => ["Marked orphaned background jobs", count]);
209
+ }
210
+ }
211
+ catch (error) {
212
+ this.logger.error(() => ["Failed to mark orphaned jobs:", error]);
213
+ }
214
+ }
215
+ }
216
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZ3JvdW5kLWpvYnMvbWFpbi5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxHQUFHLE1BQU0sS0FBSyxDQUFBO0FBQ3JCLE9BQU8sVUFBVSxNQUFNLGtCQUFrQixDQUFBO0FBQ3pDLE9BQU8sbUJBQW1CLE1BQU0sWUFBWSxDQUFBO0FBQzVDLE9BQU8sRUFBQyxNQUFNLEVBQUMsTUFBTSxjQUFjLENBQUE7QUFFbkMsTUFBTSxDQUFDLE9BQU8sT0FBTyxrQkFBa0I7SUFDckM7Ozs7O09BS0c7SUFDSCxZQUFZLEVBQUMsYUFBYSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUM7UUFDckMsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUE7UUFDbEMsTUFBTSxNQUFNLEdBQUcsYUFBYSxDQUFDLHVCQUF1QixFQUFFLENBQUE7UUFDdEQsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQTtRQUMvQixJQUFJLENBQUMsSUFBSSxHQUFHLE9BQU8sSUFBSSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFBO1FBQ3pELElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxtQkFBbUIsQ0FBQyxFQUFDLGFBQWEsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLENBQUMsa0JBQWtCLEVBQUMsQ0FBQyxDQUFBO1FBQ3BHLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDOUIsOEJBQThCO1FBQzlCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQTtRQUN4Qiw4QkFBOEI7UUFDOUIsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFBO1FBQzdCLElBQUksQ0FBQyxZQUFZLEdB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QUFFLENBQUM7Z0JBQ2QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxpQ0FBaUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFBO1lBQ3BFLENBQUM7UUFDSCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsK0JBQStCLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQTtRQUNuRSxDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBuZXQgZnJvbSBcIm5ldFwiXG5pbXBvcnQgSnNvblNvY2tldCBmcm9tIFwiLi9qc29uLXNvY2tldC5qc1wiXG5pbXBvcnQgQmFja2dyb3VuZEpvYnNTdG9yZSBmcm9tIFwiLi9zdG9yZS5qc1wiXG5pbXBvcnQge0xvZ2dlcn0gZnJvbSBcIi4uL2xvZ2dlci5qc1wiXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEJhY2tncm91bmRKb2JzTWFpbiB7XG4gIC8qKlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSBhcmdzLmNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3MuaG9zdF0gLSBIb3N0bmFtZS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFthcmdzLnBvcnRdIC0gUG9ydC5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHtjb25maWd1cmF0aW9uLCBob3N0LCBwb3J0fSkge1xuICAgIHRoaXMuY29uZmlndXJhdGlvbiA9IGNvbmZpZ3VyYXRpb25cbiAgICBjb25zdCBjb25maWcgPSBjb25maWd1cmF0aW9uLmdldEJhY2tncm91bmRKb2JzQ29uZmlnKClcbiAgICB0aGlzLmhvc3QgPSBob3N0IHx8IGNvbmZpZy5ob3N0XG4gICAgdGhpcy5wb3J0ID0gdHlwZW9mIHBvcnQgPT09IFwibnVtYmVyXCIgPyBwb3J0IDogY29uZmlnLnBvcnRcbiAgICB0aGlzLnN0b3JlID0gbmV3IEJhY2tncm91bmRKb2JzU3RvcmUoe2NvbmZpZ3VyYXRpb24sIGRhdGFiYXNlSWRlbnRpZmllcjogY29uZmlnLmRhdGFiYXNlSWRlbnRpZmllcn0pXG4gICAgdGhpcy5sb2dnZXIgPSBuZXcgTG9nZ2VyKHRoaXMpXG4gICAgLyoqIEB0eXBlIHtTZXQ8SnNvblNvY2tldD59ICovXG4gICAgdGhpcy53b3JrZXJzID0gbmV3IFNldCgpXG4gICAgLyoqIEB0eXBlIHtTZXQ8SnNvblNvY2tldD59ICovXG4gICAgdGhpcy5yZWFkeVdvcmtlcnMgPSBuZXcgU2V0KClcbiAgICB0aGlzLl9kaXNwYXRjaGluZyA9IGZhbHNlXG4gIH1cblxuICAvKipcbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBsaXN0ZW5pbmcuXG4gICAqL1xuICBhc3luYyBzdGFydCgpIHtcbiAgICB0aGlzLmNvbmZpZ3VyYXRpb24uc2V0Q3VycmVudCgpXG4gICAgYXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLmluaXRpYWxpemUoe3R5cGU6IFwiYmFja2dyb3VuZC1qb2JzLW1haW5cIn0pXG4gICAgYXdhaXQgdGhpcy5zdG9yZS5lbnN1cmVSZWFkeSgpXG4gICAgdGhpcy5zZXJ2ZXIgPSBuZXQuY3JlYXRlU2VydmVyKChzb2NrZXQpID0+IHRoaXMuX2hhbmRsZUNvbm5lY3Rpb24oc29ja2V0KSlcblxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHRoaXMuc2VydmVyLm9uY2UoXCJlcnJvclwiLCByZWplY3QpXG4gICAgICB0aGlzLnNlcnZlci5saXN0ZW4odGhpcy5wb3J0LCB0aGlzLmhvc3QsICgpID0+IHJlc29sdmUodW5kZWZpbmVkKSlcbiAgICB9KVxuXG4gICAgY29uc3QgYWRkcmVzcyA9IHRoaXMuc2VydmVyLmFkZHJlc3MoKVxuICAgIGlmIChhZGRyZXNzICYmIHR5cGVvZiBhZGRyZXNzID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLnBvcnQgPSBhZGRyZXNzLnBvcnRcbiAgICB9XG5cbiAgICB0aGlzLl9kaXNwYXRjaFRpbWVyID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgdm9pZCB0aGlzLl9kaXNwYXRjaCgpXG4gICAgfSwgMTAwMClcblxuICAgIHRoaXMuX29ycGhhblRpbWVyID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgdm9pZCB0aGlzLl9zd2VlcE9ycGhhbnMoKVxuICAgIH0sIDYwMDAwKVxuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY2xvc2VkLlxuICAgKi9cbiAgYXN5bmMgc3RvcCgpIHtcbiAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiB0aGlzLndvcmtlcnMpIHtcbiAgICAgIHdvcmtlci5jbG9zZSgpXG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2Rpc3BhdGNoVGltZXIpIGNsZWFySW50ZXJ2YWwodGhpcy5fZGlzcGF0Y2hUaW1lcilcbiAgICBpZiAodGhpcy5fb3JwaGFuVGltZXIpIGNsZWFySW50ZXJ2YWwodGhpcy5fb3JwaGFuVGltZXIpXG5cbiAgICBpZiAoIXRoaXMuc2VydmVyKSByZXR1cm5cblxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB0aGlzLnNlcnZlci5jbG9zZSgoKSA9PiByZXNvbHZlKHVuZGVmaW5lZCkpKVxuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQm91bmQgcG9ydC5cbiAgICovXG4gIGdldFBvcnQoKSB7XG4gICAgcmV0dXJuIHRoaXMucG9ydFxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwibmV0XCIpLlNvY2tldH0gc29ja2V0IC0gU29ja2V0LlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIF9oYW5kbGVDb25uZWN0aW9uKHNvY2tldCkge1xuICAgIGNvbnN0IGpzb25Tb2NrZXQgPSBuZXcgSnNvblNvY2tldChzb2NrZXQpXG4gICAgbGV0IHJvbGUgPSBudWxsXG5cbiAgICBjb25zdCBjbGVhbnVwID0gKCkgPT4ge1xuICAgICAgaWYgKHJvbGUgPT09IFwid29ya2VyXCIpIHtcbiAgICAgICAgdGhpcy53b3JrZXJzLmRlbGV0ZShqc29uU29ja2V0KVxuICAgICAgICB0aGlzLnJlYWR5V29ya2Vycy5kZWxldGUoanNvblNvY2tldClcbiAgICAgIH1cbiAgICB9XG5cbiAgICBqc29uU29ja2V0Lm9uKFwiY2xvc2VcIiwgY2xlYW51cClcbiAgICBqc29uU29ja2V0Lm9uKFwiZXJyb3JcIiwgKGVycm9yKSA9PiB7XG4gICAgICB0aGlzLmxvZ2dlci53YXJuKCgpID0+IFtcIkJhY2tncm91bmQgam9icyBjb25uZWN0aW9uIGVycm9yOlwiLCBlcnJvcl0pXG4gICAgICBjbGVhbnVwKClcbiAgICB9KVxuXG4gICAganNvblNvY2tldC5vbihcIm1lc3NhZ2VcIiwgKG1lc3NhZ2UpID0+IHtcbiAgICAgIGlmICghcm9sZSAmJiBtZXNzYWdlPy50eXBlID09PSBcImhlbGxvXCIpIHtcbiAgICAgICAgcm9sZSA9IG1lc3NhZ2Uucm9sZVxuXG4gICAgICAgIGlmIChyb2xlID09PSBcIndvcmtlclwiKSB7XG4gICAgICAgICAganNvblNvY2tldC53b3JrZXJJZCA9IG1lc3NhZ2Uud29ya2VySWRcbiAgICAgICAgICB0aGlzLndvcmtlcnMuYWRkKGpzb25Tb2NrZXQpXG4gICAgICAgICAgdGhpcy5yZWFkeVdvcmtlcnMuYWRkKGpzb25Tb2NrZXQpXG4gICAgICAgICAgdGhpcy5fZGlzcGF0Y2goKVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGlmIChyb2xlID09PSBcImNsaWVudFwiICYmIG1lc3NhZ2U/LnR5cGUgPT09IFwiZW5xdWV1ZVwiKSB7XG4gICAgICAgIHRoaXMuX2hhbmRsZUVucXVldWUoe2pzb25Tb2NrZXQsIG1lc3NhZ2V9KVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgaWYgKHJvbGUgPT09IFwid29ya2VyXCIgJiYgbWVzc2FnZT8udHlwZSA9PT0gXCJyZWFkeVwiKSB7XG4gICAgICAgIHRoaXMucmVhZHlXb3JrZXJzLmFkZChqc29uU29ja2V0KVxuICAgICAgICB0aGlzLl9kaXNwYXRjaCgpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBpZiAoKHJvbGUgPT09IFwid29ya2VyXCIgfHwgcm9sZSA9PT0gXCJyZXBvcnRlclwiKSAmJiBtZXNzYWdlPy50eXBlID09PSBcImpvYi1jb21wbGV0ZVwiKSB7XG4gICAgICAgIHRoaXMuX2hhbmRsZUpvYkNvbXBsZXRlKHtqc29uU29ja2V0LCBtZXNzYWdlfSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGlmICgocm9sZSA9PT0gXCJ3b3JrZXJcIiB8fCByb2xlID09PSBcInJlcG9ydGVyXCIpICYmIG1lc3NhZ2U/LnR5cGUgPT09IFwiam9iLWZhaWxlZFwiKSB7XG4gICAgICAgIHRoaXMuX2hhbmRsZUpvYkZhaWxlZCh7anNvblNvY2tldCwgbWVzc2FnZX0pXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIGFzeW5jIF9oYW5kbGVFbnF1ZXVlKHtqc29uU29ja2V0LCBtZXNzYWdlfSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBqb2JJZCA9IGF3YWl0IHRoaXMuc3RvcmUuZW5xdWV1ZSh7XG4gICAgICAgIGpvYk5hbWU6IG1lc3NhZ2Uuam9iTmFtZSxcbiAgICAgICAgYXJnczogbWVzc2FnZS5hcmdzIHx8IFtdLFxuICAgICAgICBvcHRpb25zOiBtZXNzYWdlLm9wdGlvbnMgfHwge31cbiAgICAgIH0pXG5cbiAgICAgIGpzb25Tb2NrZXQuc2VuZCh7dHlwZTogXCJlbnF1ZXVlZFwiLCBqb2JJZH0pXG4gICAgICBhd2FpdCB0aGlzLl9kaXNwYXRjaCgpXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKCgpID0+IFtcIkZhaWxlZCB0byBlbnF1ZXVlIGJhY2tncm91bmQgam9iOlwiLCBlcnJvcl0pXG4gICAgICBqc29uU29ja2V0LnNlbmQoe3R5cGU6IFwiZW5xdWV1ZS1lcnJvclwiLCBlcnJvcjogXCJGYWlsZWQgdG8gZW5xdWV1ZSBqb2JcIn0pXG4gICAgfVxuICB9XG5cbiAgYXN5bmMgX2hhbmRsZUpvYkNvbXBsZXRlKHtqc29uU29ja2V0LCBtZXNzYWdlfSkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnN0b3JlLm1hcmtDb21wbGV0ZWQoe1xuICAgICAgICBqb2JJZDogbWVzc2FnZS5qb2JJZCxcbiAgICAgICAgd29ya2VySWQ6IG1lc3NhZ2Uud29ya2VySWQsXG4gICAgICAgIGhhbmRlZE9mZkF0TXM6IG1lc3NhZ2UuaGFuZGVkT2ZmQXRNc1xuICAgICAgfSlcbiAgICAgIGpzb25Tb2NrZXQuc2VuZCh7dHlwZTogXCJqb2ItdXBkYXRlZFwiLCBqb2JJZDogbWVzc2FnZS5qb2JJZH0pXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKCgpID0+IFtcIkZhaWxlZCB0byB1cGRhdGUgam9iIGNvbXBsZXRpb246XCIsIGVycm9yXSlcbiAgICAgIGpzb25Tb2NrZXQuc2VuZCh7dHlwZTogXCJqb2ItdXBkYXRlLWVycm9yXCIsIGpvYklkOiBtZXNzYWdlLmpvYklkLCBlcnJvcjogXCJGYWlsZWQgdG8gdXBkYXRlIGpvYlwifSlcbiAgICB9XG4gIH1cblxuICBhc3luYyBfaGFuZGxlSm9iRmFpbGVkKHtqc29uU29ja2V0LCBtZXNzYWdlfSkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnN0b3JlLm1hcmtGYWlsZWQoe1xuICAgICAgICBqb2JJZDogbWVzc2FnZS5qb2JJZCxcbiAgICAgICAgZXJyb3I6IG1lc3NhZ2UuZXJyb3IsXG4gICAgICAgIHdvcmtlcklkOiBtZXNzYWdlLndvcmtlcklkLFxuICAgICAgICBoYW5kZWRPZmZBdE1zOiBtZXNzYWdlLmhhbmRlZE9mZkF0TXNcbiAgICAgIH0pXG4gICAgICBqc29uU29ja2V0LnNlbmQoe3R5cGU6IFwiam9iLXVwZGF0ZWRcIiwgam9iSWQ6IG1lc3NhZ2Uuam9iSWR9KVxuICAgICAgYXdhaXQgdGhpcy5fZGlzcGF0Y2goKVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLmxvZ2dlci5lcnJvcigoKSA9PiBbXCJGYWlsZWQgdG8gdXBkYXRlIGpvYiBmYWlsdXJlOlwiLCBlcnJvcl0pXG4gICAgICBqc29uU29ja2V0LnNlbmQoe3R5cGU6IFwiam9iLXVwZGF0ZS1lcnJvclwiLCBqb2JJZDogbWVzc2FnZS5qb2JJZCwgZXJyb3I6IFwiRmFpbGVkIHRvIHVwZGF0ZSBqb2JcIn0pXG4gICAgfVxuICB9XG5cbiAgYXN5bmMgX2Rpc3BhdGNoKCkge1xuICAgIGlmICh0aGlzLl9kaXNwYXRjaGluZykgcmV0dXJuXG4gICAgaWYgKHRoaXMucmVhZHlXb3JrZXJzLnNpemUgPT09IDApIHJldHVyblxuXG4gICAgdGhpcy5fZGlzcGF0Y2hpbmcgPSB0cnVlXG5cbiAgICB0cnkge1xuICAgICAgd2hpbGUgKHRoaXMucmVhZHlXb3JrZXJzLnNpemUgPiAwKSB7XG4gICAgICAgIGNvbnN0IGpvYiA9IGF3YWl0IHRoaXMuc3RvcmUubmV4dEF2YWlsYWJsZUpvYigpXG4gICAgICAgIGlmICgham9iKSByZXR1cm5cblxuICAgICAgICBjb25zdCBbd29ya2VyXSA9IHRoaXMucmVhZHlXb3JrZXJzXG4gICAgICAgIGlmICghd29ya2VyKSByZXR1cm5cblxuICAgICAgICB0aGlzLnJlYWR5V29ya2Vycy5kZWxldGUod29ya2VyKVxuXG4gICAgICAgIGNvbnN0IGhhbmRlZE9mZkF0TXMgPSBhd2FpdCB0aGlzLnN0b3JlLm1hcmtIYW5kZWRPZmYoe2pvYklkOiBqb2IuaWQsIHdvcmtlcklkOiB3b3JrZXIud29ya2VySWR9KVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgd29ya2VyLnNlbmQoe1xuICAgICAgICAgICAgdHlwZTogXCJqb2JcIixcbiAgICAgICAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAgICAgICAgaWQ6IGpvYi5pZCxcbiAgICAgICAgICAgICAgam9iTmFtZTogam9iLmpvYk5hbWUsXG4gICAgICAgICAgICAgIGFyZ3M6IGpvYi5hcmdzLFxuICAgICAgICAgICAgICB3b3JrZXJJZDogd29ya2VyLndvcmtlcklkLFxuICAgICAgICAgICAgICBoYW5kZWRPZmZBdE1zLFxuICAgICAgICAgICAgICBvcHRpb25zOiB7XG4gICAgICAgICAgICAgICAgZm9ya2VkOiBqb2IuZm9ya2VkXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KVxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIHRoaXMubG9nZ2VyLndhcm4oKCkgPT4gW1wiRmFpbGVkIHRvIHNlbmQgam9iIHRvIHdvcmtlciwgcmUtcXVldWVpbmc6XCIsIGVycm9yXSlcbiAgICAgICAgICBhd2FpdCB0aGlzLnN0b3JlLm1hcmtSZXR1cm5lZFRvUXVldWUoe2pvYklkOiBqb2IuaWR9KVxuICAgICAgICAgIHRoaXMucmVhZHlXb3JrZXJzLmFkZCh3b3JrZXIpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5fZGlzcGF0Y2hpbmcgPSBmYWxzZVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIF9zd2VlcE9ycGhhbnMoKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNvdW50ID0gYXdhaXQgdGhpcy5zdG9yZS5tYXJrT3JwaGFuZWRKb2JzKClcblxuICAgICAgaWYgKGNvdW50ID4gMCkge1xuICAgICAgICB0aGlzLmxvZ2dlci53YXJuKCgpID0+IFtcIk1hcmtlZCBvcnBoYW5lZCBiYWNrZ3JvdW5kIGpvYnNcIiwgY291bnRdKVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLmxvZ2dlci5lcnJvcigoKSA9PiBbXCJGYWlsZWQgdG8gbWFyayBvcnBoYW5lZCBqb2JzOlwiLCBlcnJvcl0pXG4gICAgfVxuICB9XG59XG4iXX0=
@@ -0,0 +1,54 @@
1
+ export default class BackgroundJobsStatusReporter {
2
+ /**
3
+ * @param {object} args - Options.
4
+ * @param {import("../configuration.js").default} args.configuration - Configuration.
5
+ * @param {string} [args.host] - Host.
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
+ configuration: import("../configuration.js").default;
14
+ host: string;
15
+ port: number;
16
+ logger: Logger;
17
+ /**
18
+ * @param {object} args - Options.
19
+ * @param {string} args.jobId - Job id.
20
+ * @param {"completed" | "failed"} args.status - Status.
21
+ * @param {unknown} [args.error] - Error.
22
+ * @param {number} [args.handedOffAtMs] - Handed off timestamp.
23
+ * @param {string} [args.workerId] - Worker id.
24
+ * @returns {Promise<void>} - Resolves when reported.
25
+ */
26
+ report({ jobId, status, error, handedOffAtMs, workerId }: {
27
+ jobId: string;
28
+ status: "completed" | "failed";
29
+ error?: unknown;
30
+ handedOffAtMs?: number;
31
+ workerId?: string;
32
+ }): Promise<void>;
33
+ /**
34
+ * @param {object} args - Options.
35
+ * @param {string} args.jobId - Job id.
36
+ * @param {"completed" | "failed"} args.status - Status.
37
+ * @param {unknown} [args.error] - Error.
38
+ * @param {number} [args.handedOffAtMs] - Handed off timestamp.
39
+ * @param {string} [args.workerId] - Worker id.
40
+ * @param {number} [args.maxDurationMs] - Max duration for retries.
41
+ * @returns {Promise<void>} - Resolves when reported.
42
+ */
43
+ reportWithRetry({ jobId, status, error, handedOffAtMs, workerId, maxDurationMs }: {
44
+ jobId: string;
45
+ status: "completed" | "failed";
46
+ error?: unknown;
47
+ handedOffAtMs?: number;
48
+ workerId?: string;
49
+ maxDurationMs?: number;
50
+ }): Promise<void>;
51
+ _normalizeError(error: any): string;
52
+ }
53
+ import { Logger } from "../logger.js";
54
+ //# sourceMappingURL=status-reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-reporter.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/status-reporter.js"],"names":[],"mappings":"AAQA;IACE;;;;;OAKG;IACH,2CAJG;QAAoD,aAAa,EAAzD,OAAO,qBAAqB,EAAE,OAAO;QACvB,IAAI,GAAlB,MAAM;QACQ,IAAI,GAAlB,MAAM;KAChB,EAMA;IAJC,qDAAkC;IAClC,aAAgB;IAChB,aAAgB;IAChB,eAA8B;IAGhC;;;;;;;;OAQG;IACH,0DAPG;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,CAgDzB;IAED;;;;;;;;;OASG;IACH,kFARG;QAAqB,KAAK,EAAlB,MAAM;QACuB,MAAM,EAAnC,WAAW,GAAG,QAAQ;QACP,KAAK,GAApB,OAAO;QACO,aAAa,GAA3B,MAAM;QACQ,QAAQ,GAAtB,MAAM;QACQ,aAAa,GAA3B,MAAM;KACd,GAAU,OAAO,CAAC,IAAI,CAAC,CAwBzB;IAED,oCASC;CACF;uBArHoB,cAAc"}
@@ -0,0 +1,113 @@
1
+ // @ts-check
2
+ import net from "net";
3
+ import timeout from "awaitery/build/timeout.js";
4
+ import wait from "awaitery/build/wait.js";
5
+ import JsonSocket from "./json-socket.js";
6
+ import { Logger } from "../logger.js";
7
+ export default class BackgroundJobsStatusReporter {
8
+ /**
9
+ * @param {object} args - Options.
10
+ * @param {import("../configuration.js").default} args.configuration - Configuration.
11
+ * @param {string} [args.host] - Host.
12
+ * @param {number} [args.port] - Port.
13
+ */
14
+ constructor({ configuration, host, port }) {
15
+ this.configuration = configuration;
16
+ this.host = host;
17
+ this.port = port;
18
+ this.logger = new Logger(this);
19
+ }
20
+ /**
21
+ * @param {object} args - Options.
22
+ * @param {string} args.jobId - Job id.
23
+ * @param {"completed" | "failed"} args.status - Status.
24
+ * @param {unknown} [args.error] - Error.
25
+ * @param {number} [args.handedOffAtMs] - Handed off timestamp.
26
+ * @param {string} [args.workerId] - Worker id.
27
+ * @returns {Promise<void>} - Resolves when reported.
28
+ */
29
+ async report({ jobId, status, error, handedOffAtMs, workerId }) {
30
+ const config = this.configuration.getBackgroundJobsConfig();
31
+ const host = this.host || config.host;
32
+ const port = typeof this.port === "number" ? this.port : config.port;
33
+ await timeout({ timeout: 5000 }, async () => {
34
+ await new Promise((resolve, reject) => {
35
+ const socket = net.createConnection({ host, port });
36
+ const jsonSocket = new JsonSocket(socket);
37
+ const cleanup = () => {
38
+ jsonSocket.removeAllListeners();
39
+ };
40
+ jsonSocket.on("error", (err) => {
41
+ cleanup();
42
+ reject(err);
43
+ });
44
+ jsonSocket.on("message", (message) => {
45
+ if (message?.type === "job-updated" && message.jobId === jobId) {
46
+ cleanup();
47
+ jsonSocket.close();
48
+ resolve(undefined);
49
+ return;
50
+ }
51
+ if (message?.type === "job-update-error" && message.jobId === jobId) {
52
+ cleanup();
53
+ jsonSocket.close();
54
+ reject(new Error(message.error || "Job update failed"));
55
+ }
56
+ });
57
+ socket.on("connect", () => {
58
+ jsonSocket.send({ type: "hello", role: "reporter" });
59
+ jsonSocket.send({
60
+ type: status === "completed" ? "job-complete" : "job-failed",
61
+ jobId,
62
+ workerId,
63
+ handedOffAtMs,
64
+ error: error ? this._normalizeError(error) : undefined
65
+ });
66
+ });
67
+ });
68
+ });
69
+ }
70
+ /**
71
+ * @param {object} args - Options.
72
+ * @param {string} args.jobId - Job id.
73
+ * @param {"completed" | "failed"} args.status - Status.
74
+ * @param {unknown} [args.error] - Error.
75
+ * @param {number} [args.handedOffAtMs] - Handed off timestamp.
76
+ * @param {string} [args.workerId] - Worker id.
77
+ * @param {number} [args.maxDurationMs] - Max duration for retries.
78
+ * @returns {Promise<void>} - Resolves when reported.
79
+ */
80
+ async reportWithRetry({ jobId, status, error, handedOffAtMs, workerId, maxDurationMs }) {
81
+ let attempt = 0;
82
+ const startTime = Date.now();
83
+ while (true) {
84
+ try {
85
+ await this.report({ jobId, status, error, handedOffAtMs, workerId });
86
+ return;
87
+ }
88
+ catch (err) {
89
+ attempt += 1;
90
+ const delaySeconds = Math.min(30, 0.5 * attempt);
91
+ this.logger.debug(() => ["Background job status report failed, retrying", err]);
92
+ if (maxDurationMs && Date.now() - startTime >= maxDurationMs) {
93
+ this.logger.warn(() => ["Background job status report timed out, giving up", err]);
94
+ return;
95
+ }
96
+ await wait(delaySeconds);
97
+ }
98
+ }
99
+ }
100
+ _normalizeError(error) {
101
+ if (error instanceof Error)
102
+ return error.stack || error.message;
103
+ if (typeof error === "string")
104
+ return error;
105
+ try {
106
+ return JSON.stringify(error);
107
+ }
108
+ catch {
109
+ return String(error);
110
+ }
111
+ }
112
+ }
113
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdHVzLXJlcG9ydGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2JhY2tncm91bmQtam9icy9zdGF0dXMtcmVwb3J0ZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sR0FBRyxNQUFNLEtBQUssQ0FBQTtBQUNyQixPQUFPLE9BQU8sTUFBTSwyQkFBMkIsQ0FBQTtBQUMvQyxPQUFPLElBQUksTUFBTSx3QkFBd0IsQ0FBQTtBQUN6QyxPQUFPLFVBQVUsTUFBTSxrQkFBa0IsQ0FBQTtBQUN6QyxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sY0FBYyxDQUFBO0FBRW5DLE1BQU0sQ0FBQyxPQUFPLE9BQU8sNEJBQTRCO0lBQy9DOzs7OztPQUtHO0lBQ0gsWUFBWSxFQUFDLGFBQWEsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFDO1FBQ3JDLElBQUksQ0FBQyxhQUFhLEdBQUcsYUFBYSxDQUFBO1FBQ2xDLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFBO1FBQ2hCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFBO1FBQ2hCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDaEMsQ0FBQztJQUVEOzs7Ozs7OztPQVFHO0lBQ0gsS0FBSyxDQUFDLE1BQU0sQ0FBQyxFQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxRQUFRLEVBQUM7UUFDMUQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyx1QkFBdUIsRUFBRSxDQUFBO1FBQzNELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQTtRQUNyQyxNQUFNLElBQUksR0FBRyxPQUFPLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FB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LE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEdBQUcsR0FBRyxPQUFPLENBQUMsQ0FBQTtnQkFFaEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQywrQ0FBK0MsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFBO2dCQUUvRSxJQUFJLGFBQWEsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxJQUFJLGFBQWEsRUFBRSxDQUFDO29CQUM3RCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLG1EQUFtRCxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUE7b0JBQ2xGLE9BQU07Z0JBQ1IsQ0FBQztnQkFFRCxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQTtZQUMxQixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCxlQUFlLENBQUMsS0FBSztRQUNuQixJQUFJLEtBQUssWUFBWSxLQUFLO1lBQUUsT0FBTyxLQUFLLENBQUMsS0FBSyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUE7UUFDL0QsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRO1lBQUUsT0FBTyxLQUFLLENBQUE7UUFFM0MsSUFBSSxDQUFDO1lBQ0gsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBQzlCLENBQUM7UUFBQyxNQUFNLENBQUM7WUFDUCxPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUN0QixDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBuZXQgZnJvbSBcIm5ldFwiXG5pbXBvcnQgdGltZW91dCBmcm9tIFwiYXdhaXRlcnkvYnVpbGQvdGltZW91dC5qc1wiXG5pbXBvcnQgd2FpdCBmcm9tIFwiYXdhaXRlcnkvYnVpbGQvd2FpdC5qc1wiXG5pbXBvcnQgSnNvblNvY2tldCBmcm9tIFwiLi9qc29uLXNvY2tldC5qc1wiXG5pbXBvcnQge0xvZ2dlcn0gZnJvbSBcIi4uL2xvZ2dlci5qc1wiXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEJhY2tncm91bmRKb2JzU3RhdHVzUmVwb3J0ZXIge1xuICAvKipcbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH0gYXJncy5jb25maWd1cmF0aW9uIC0gQ29uZmlndXJhdGlvbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcmdzLmhvc3RdIC0gSG9zdC5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFthcmdzLnBvcnRdIC0gUG9ydC5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHtjb25maWd1cmF0aW9uLCBob3N0LCBwb3J0fSkge1xuICAgIHRoaXMuY29uZmlndXJhdGlvbiA9IGNvbmZpZ3VyYXRpb25cbiAgICB0aGlzLmhvc3QgPSBob3N0XG4gICAgdGhpcy5wb3J0ID0gcG9ydFxuICAgIHRoaXMubG9nZ2VyID0gbmV3IExvZ2dlcih0aGlzKVxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muam9iSWQgLSBKb2IgaWQuXG4gICAqIEBwYXJhbSB7XCJjb21wbGV0ZWRcIiB8IFwiZmFpbGVkXCJ9IGFyZ3Muc3RhdHVzIC0gU3RhdHVzLlxuICAgKiBAcGFyYW0ge3Vua25vd259IFthcmdzLmVycm9yXSAtIEVycm9yLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3MuaGFuZGVkT2ZmQXRNc10gLSBIYW5kZWQgb2ZmIHRpbWVzdGFtcC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcmdzLndvcmtlcklkXSAtIFdvcmtlciBpZC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiByZXBvcnRlZC5cbiAgICovXG4gIGFzeW5jIHJlcG9ydCh7am9iSWQsIHN0YXR1cywgZXJyb3IsIGhhbmRlZE9mZkF0TXMsIHdvcmtlcklkfSkge1xuICAgIGNvbnN0IGNvbmZpZyA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRCYWNrZ3JvdW5kSm9ic0NvbmZpZygpXG4gICAgY29uc3QgaG9zdCA9IHRoaXMuaG9zdCB8fCBjb25maWcuaG9zdFxuICAgIGNvbnN0IHBvcnQgPSB0eXBlb2YgdGhpcy5wb3J0ID09PSBcIm51bWJlclwiID8gdGhpcy5wb3J0IDogY29uZmlnLnBvcnRcblxuICAgIGF3YWl0IHRpbWVvdXQoe3RpbWVvdXQ6IDUwMDB9LCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGNvbnN0IHNvY2tldCA9IG5ldC5jcmVhdGVDb25uZWN0aW9uKHtob3N0LCBwb3J0fSlcbiAgICAgICAgY29uc3QganNvblNvY2tldCA9IG5ldyBKc29uU29ja2V0KHNvY2tldClcblxuICAgICAgICBjb25zdCBjbGVhbnVwID0gKCkgPT4ge1xuICAgICAgICAgIGpzb25Tb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKClcbiAgICAgICAgfVxuXG4gICAgICAgIGpzb25Tb2NrZXQub24oXCJlcnJvclwiLCAoZXJyKSA9PiB7XG4gICAgICAgICAgY2xlYW51cCgpXG4gICAgICAgICAgcmVqZWN0KGVycilcbiAgICAgICAgfSlcblxuICAgICAgICBqc29uU29ja2V0Lm9uKFwibWVzc2FnZVwiLCAobWVzc2FnZSkgPT4ge1xuICAgICAgICAgIGlmIChtZXNzYWdlPy50eXBlID09PSBcImpvYi11cGRhdGVkXCIgJiYgbWVzc2FnZS5qb2JJZCA9PT0gam9iSWQpIHtcbiAgICAgICAgICAgIGNsZWFudXAoKVxuICAgICAgICAgICAganNvblNvY2tldC5jbG9zZSgpXG4gICAgICAgICAgICByZXNvbHZlKHVuZGVmaW5lZClcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChtZXNzYWdlPy50eXBlID09PSBcImpvYi11cGRhdGUtZXJyb3JcIiAmJiBtZXNzYWdlLmpvYklkID09PSBqb2JJZCkge1xuICAgICAgICAgICAgY2xlYW51cCgpXG4gICAgICAgICAgICBqc29uU29ja2V0LmNsb3NlKClcbiAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IobWVzc2FnZS5lcnJvciB8fCBcIkpvYiB1cGRhdGUgZmFpbGVkXCIpKVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcblxuICAgICAgICBzb2NrZXQub24oXCJjb25uZWN0XCIsICgpID0+IHtcbiAgICAgICAgICBqc29uU29ja2V0LnNlbmQoe3R5cGU6IFwiaGVsbG9cIiwgcm9sZTogXCJyZXBvcnRlclwifSlcbiAgICAgICAgICBqc29uU29ja2V0LnNlbmQoe1xuICAgICAgICAgICAgdHlwZTogc3RhdHVzID09PSBcImNvbXBsZXRlZFwiID8gXCJqb2ItY29tcGxldGVcIiA6IFwiam9iLWZhaWxlZFwiLFxuICAgICAgICAgICAgam9iSWQsXG4gICAgICAgICAgICB3b3JrZXJJZCxcbiAgICAgICAgICAgIGhhbmRlZE9mZkF0TXMsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IgPyB0aGlzLl9ub3JtYWxpemVFcnJvcihlcnJvcikgOiB1bmRlZmluZWRcbiAgICAgICAgICB9KVxuICAgICAgICB9KVxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muam9iSWQgLSBKb2IgaWQuXG4gICAqIEBwYXJhbSB7XCJjb21wbGV0ZWRcIiB8IFwiZmFpbGVkXCJ9IGFyZ3Muc3RhdHVzIC0gU3RhdHVzLlxuICAgKiBAcGFyYW0ge3Vua25vd259IFthcmdzLmVycm9yXSAtIEVycm9yLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3MuaGFuZGVkT2ZmQXRNc10gLSBIYW5kZWQgb2ZmIHRpbWVzdGFtcC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcmdzLndvcmtlcklkXSAtIFdvcmtlciBpZC5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFthcmdzLm1heER1cmF0aW9uTXNdIC0gTWF4IGR1cmF0aW9uIGZvciByZXRyaWVzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIHJlcG9ydGVkLlxuICAgKi9cbiAgYXN5bmMgcmVwb3J0V2l0aFJldHJ5KHtqb2JJZCwgc3RhdHVzLCBlcnJvciwgaGFuZGVkT2ZmQXRNcywgd29ya2VySWQsIG1heER1cmF0aW9uTXN9KSB7XG4gICAgbGV0IGF0dGVtcHQgPSAwXG4gICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKVxuXG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVwb3J0KHtqb2JJZCwgc3RhdHVzLCBlcnJvciwgaGFuZGVkT2ZmQXRNcywgd29ya2VySWR9KVxuICAgICAgICByZXR1cm5cbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBhdHRlbXB0ICs9IDFcbiAgICAgICAgY29uc3QgZGVsYXlTZWNvbmRzID0gTWF0aC5taW4oMzAsIDAuNSAqIGF0dGVtcHQpXG5cbiAgICAgICAgdGhpcy5sb2dnZXIuZGVidWcoKCkgPT4gW1wiQmFja2dyb3VuZCBqb2Igc3RhdHVzIHJlcG9ydCBmYWlsZWQsIHJldHJ5aW5nXCIsIGVycl0pXG5cbiAgICAgICAgaWYgKG1heER1cmF0aW9uTXMgJiYgRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSA+PSBtYXhEdXJhdGlvbk1zKSB7XG4gICAgICAgICAgdGhpcy5sb2dnZXIud2FybigoKSA9PiBbXCJCYWNrZ3JvdW5kIGpvYiBzdGF0dXMgcmVwb3J0IHRpbWVkIG91dCwgZ2l2aW5nIHVwXCIsIGVycl0pXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCB3YWl0KGRlbGF5U2Vjb25kcylcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBfbm9ybWFsaXplRXJyb3IoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikgcmV0dXJuIGVycm9yLnN0YWNrIHx8IGVycm9yLm1lc3NhZ2VcbiAgICBpZiAodHlwZW9mIGVycm9yID09PSBcInN0cmluZ1wiKSByZXR1cm4gZXJyb3JcblxuICAgIHRyeSB7XG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoZXJyb3IpXG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gU3RyaW5nKGVycm9yKVxuICAgIH1cbiAgfVxufVxuIl19