@constructive-io/knative-job-worker 0.7.15 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +55 -5
- package/package.json +6 -6
- package/src/index.ts +60 -8
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [0.8.0](https://github.com/constructive-io/jobs/compare/@constructive-io/knative-job-worker@0.7.16...@constructive-io/knative-job-worker@0.8.0) (2026-01-18)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @constructive-io/knative-job-worker
|
|
9
|
+
|
|
10
|
+
## [0.7.16](https://github.com/constructive-io/jobs/compare/@constructive-io/knative-job-worker@0.7.15...@constructive-io/knative-job-worker@0.7.16) (2026-01-18)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @constructive-io/knative-job-worker
|
|
13
|
+
|
|
6
14
|
## [0.7.15](https://github.com/constructive-io/jobs/compare/@constructive-io/knative-job-worker@0.7.14...@constructive-io/knative-job-worker@0.7.15) (2026-01-14)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @constructive-io/knative-job-worker
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PgClientLike } from '@constructive-io/job-utils';
|
|
2
|
-
import type { Pool } from 'pg';
|
|
2
|
+
import type { Pool, PoolClient } from 'pg';
|
|
3
3
|
export interface JobRow {
|
|
4
4
|
id: number | string;
|
|
5
5
|
task_identifier: string;
|
|
@@ -13,6 +13,9 @@ export default class Worker {
|
|
|
13
13
|
doNextTimer?: NodeJS.Timeout;
|
|
14
14
|
pgPool: Pool;
|
|
15
15
|
_initialized?: boolean;
|
|
16
|
+
listenClient?: PoolClient;
|
|
17
|
+
listenRelease?: () => void;
|
|
18
|
+
stopped?: boolean;
|
|
16
19
|
constructor({ tasks, idleDelay, pgPool, workerId }: {
|
|
17
20
|
tasks: string[];
|
|
18
21
|
idleDelay?: number;
|
|
@@ -37,5 +40,6 @@ export default class Worker {
|
|
|
37
40
|
doWork(job: JobRow): Promise<void>;
|
|
38
41
|
doNext(client: PgClientLike): Promise<void>;
|
|
39
42
|
listen(): void;
|
|
43
|
+
stop(): Promise<void>;
|
|
40
44
|
}
|
|
41
45
|
export { Worker };
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,9 @@ class Worker {
|
|
|
49
49
|
doNextTimer;
|
|
50
50
|
pgPool;
|
|
51
51
|
_initialized;
|
|
52
|
+
listenClient;
|
|
53
|
+
listenRelease;
|
|
54
|
+
stopped;
|
|
52
55
|
constructor({ tasks, idleDelay = 15000, pgPool = job_pg_1.default.getPool(), workerId = 'worker-0' }) {
|
|
53
56
|
/*
|
|
54
57
|
* idleDelay: This is how long to wait between polling for jobs.
|
|
@@ -114,6 +117,8 @@ class Worker {
|
|
|
114
117
|
});
|
|
115
118
|
}
|
|
116
119
|
async doNext(client) {
|
|
120
|
+
if (this.stopped)
|
|
121
|
+
return;
|
|
117
122
|
if (!this._initialized) {
|
|
118
123
|
return await this.initialize(client);
|
|
119
124
|
}
|
|
@@ -130,7 +135,9 @@ class Worker {
|
|
|
130
135
|
: this.supportedTaskNames
|
|
131
136
|
}));
|
|
132
137
|
if (!job || !job.id) {
|
|
133
|
-
|
|
138
|
+
if (!this.stopped) {
|
|
139
|
+
this.doNextTimer = setTimeout(() => this.doNext(client), this.idleDelay);
|
|
140
|
+
}
|
|
134
141
|
return;
|
|
135
142
|
}
|
|
136
143
|
const start = process.hrtime();
|
|
@@ -155,13 +162,20 @@ class Worker {
|
|
|
155
162
|
catch (fatalError) {
|
|
156
163
|
await this.handleFatalError(client, { err, fatalError, jobId });
|
|
157
164
|
}
|
|
158
|
-
|
|
165
|
+
if (!this.stopped) {
|
|
166
|
+
return this.doNext(client);
|
|
167
|
+
}
|
|
168
|
+
return;
|
|
159
169
|
}
|
|
160
170
|
catch (err) {
|
|
161
|
-
|
|
171
|
+
if (!this.stopped) {
|
|
172
|
+
this.doNextTimer = setTimeout(() => this.doNext(client), this.idleDelay);
|
|
173
|
+
}
|
|
162
174
|
}
|
|
163
175
|
}
|
|
164
176
|
listen() {
|
|
177
|
+
if (this.stopped)
|
|
178
|
+
return;
|
|
165
179
|
const listenForChanges = (err, client, release) => {
|
|
166
180
|
if (err) {
|
|
167
181
|
log.error('Error connecting with notify listener', err);
|
|
@@ -170,9 +184,17 @@ class Worker {
|
|
|
170
184
|
}
|
|
171
185
|
// Try again in 5 seconds
|
|
172
186
|
// should this really be done in the node process?
|
|
173
|
-
|
|
187
|
+
if (!this.stopped) {
|
|
188
|
+
setTimeout(this.listen, 5000);
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (this.stopped) {
|
|
193
|
+
release();
|
|
174
194
|
return;
|
|
175
195
|
}
|
|
196
|
+
this.listenClient = client;
|
|
197
|
+
this.listenRelease = release;
|
|
176
198
|
client.on('notification', () => {
|
|
177
199
|
if (this.doNextTimer) {
|
|
178
200
|
// Must be idle, do something!
|
|
@@ -181,18 +203,46 @@ class Worker {
|
|
|
181
203
|
});
|
|
182
204
|
client.query('LISTEN "jobs:insert"');
|
|
183
205
|
client.on('error', (e) => {
|
|
206
|
+
if (this.stopped) {
|
|
207
|
+
release();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
184
210
|
log.error('Error with database notify listener', e);
|
|
185
211
|
if (e instanceof Error && e.stack) {
|
|
186
212
|
log.debug(e.stack);
|
|
187
213
|
}
|
|
188
214
|
release();
|
|
189
|
-
this.
|
|
215
|
+
if (!this.stopped) {
|
|
216
|
+
this.listen();
|
|
217
|
+
}
|
|
190
218
|
});
|
|
191
219
|
log.info(`${this.workerId} connected and looking for jobs...`);
|
|
192
220
|
this.doNext(client);
|
|
193
221
|
};
|
|
194
222
|
this.pgPool.connect(listenForChanges);
|
|
195
223
|
}
|
|
224
|
+
async stop() {
|
|
225
|
+
this.stopped = true;
|
|
226
|
+
if (this.doNextTimer) {
|
|
227
|
+
clearTimeout(this.doNextTimer);
|
|
228
|
+
this.doNextTimer = undefined;
|
|
229
|
+
}
|
|
230
|
+
const client = this.listenClient;
|
|
231
|
+
const release = this.listenRelease;
|
|
232
|
+
this.listenClient = undefined;
|
|
233
|
+
this.listenRelease = undefined;
|
|
234
|
+
if (client && release) {
|
|
235
|
+
client.removeAllListeners('notification');
|
|
236
|
+
client.removeAllListeners('error');
|
|
237
|
+
try {
|
|
238
|
+
await client.query('UNLISTEN "jobs:insert"');
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
// Ignore listener cleanup errors during shutdown.
|
|
242
|
+
}
|
|
243
|
+
release();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
196
246
|
}
|
|
197
247
|
exports.default = Worker;
|
|
198
248
|
exports.Worker = Worker;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructive-io/knative-job-worker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "knative job worker",
|
|
5
5
|
"author": "Constructive <developers@constructive.io>",
|
|
6
6
|
"homepage": "https://github.com/constructive-io/jobs/tree/master/packages/knative-job-worker#readme",
|
|
@@ -32,14 +32,14 @@
|
|
|
32
32
|
"url": "https://github.com/constructive-io/jobs/issues"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@constructive-io/job-pg": "^0.
|
|
36
|
-
"@constructive-io/job-utils": "^0.
|
|
37
|
-
"@pgpmjs/logger": "^1.
|
|
35
|
+
"@constructive-io/job-pg": "^0.4.0",
|
|
36
|
+
"@constructive-io/job-utils": "^0.6.0",
|
|
37
|
+
"@pgpmjs/logger": "^1.4.0",
|
|
38
38
|
"pg": "8.16.3",
|
|
39
39
|
"request": "2.88.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"pgsql-test": "^2.
|
|
42
|
+
"pgsql-test": "^2.25.0"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "481b3a50b4eec2da6b376c4cd1868065e1e28edb"
|
|
45
45
|
}
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,9 @@ export default class Worker {
|
|
|
21
21
|
doNextTimer?: NodeJS.Timeout;
|
|
22
22
|
pgPool: Pool;
|
|
23
23
|
_initialized?: boolean;
|
|
24
|
+
listenClient?: PoolClient;
|
|
25
|
+
listenRelease?: () => void;
|
|
26
|
+
stopped?: boolean;
|
|
24
27
|
|
|
25
28
|
constructor({
|
|
26
29
|
tasks,
|
|
@@ -118,6 +121,7 @@ export default class Worker {
|
|
|
118
121
|
});
|
|
119
122
|
}
|
|
120
123
|
async doNext(client: PgClientLike): Promise<void> {
|
|
124
|
+
if (this.stopped) return;
|
|
121
125
|
if (!this._initialized) {
|
|
122
126
|
return await this.initialize(client);
|
|
123
127
|
}
|
|
@@ -136,10 +140,12 @@ export default class Worker {
|
|
|
136
140
|
})) as JobRow | undefined;
|
|
137
141
|
|
|
138
142
|
if (!job || !job.id) {
|
|
139
|
-
this.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
if (!this.stopped) {
|
|
144
|
+
this.doNextTimer = setTimeout(
|
|
145
|
+
() => this.doNext(client),
|
|
146
|
+
this.idleDelay
|
|
147
|
+
);
|
|
148
|
+
}
|
|
143
149
|
return;
|
|
144
150
|
}
|
|
145
151
|
const start = process.hrtime();
|
|
@@ -164,12 +170,21 @@ export default class Worker {
|
|
|
164
170
|
} catch (fatalError: unknown) {
|
|
165
171
|
await this.handleFatalError(client, { err, fatalError, jobId });
|
|
166
172
|
}
|
|
167
|
-
|
|
173
|
+
if (!this.stopped) {
|
|
174
|
+
return this.doNext(client);
|
|
175
|
+
}
|
|
176
|
+
return;
|
|
168
177
|
} catch (err: unknown) {
|
|
169
|
-
|
|
178
|
+
if (!this.stopped) {
|
|
179
|
+
this.doNextTimer = setTimeout(
|
|
180
|
+
() => this.doNext(client),
|
|
181
|
+
this.idleDelay
|
|
182
|
+
);
|
|
183
|
+
}
|
|
170
184
|
}
|
|
171
185
|
}
|
|
172
186
|
listen() {
|
|
187
|
+
if (this.stopped) return;
|
|
173
188
|
const listenForChanges = (
|
|
174
189
|
err: Error | null,
|
|
175
190
|
client: PoolClient,
|
|
@@ -182,9 +197,17 @@ export default class Worker {
|
|
|
182
197
|
}
|
|
183
198
|
// Try again in 5 seconds
|
|
184
199
|
// should this really be done in the node process?
|
|
185
|
-
|
|
200
|
+
if (!this.stopped) {
|
|
201
|
+
setTimeout(this.listen, 5000);
|
|
202
|
+
}
|
|
186
203
|
return;
|
|
187
204
|
}
|
|
205
|
+
if (this.stopped) {
|
|
206
|
+
release();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
this.listenClient = client;
|
|
210
|
+
this.listenRelease = release;
|
|
188
211
|
client.on('notification', () => {
|
|
189
212
|
if (this.doNextTimer) {
|
|
190
213
|
// Must be idle, do something!
|
|
@@ -193,18 +216,47 @@ export default class Worker {
|
|
|
193
216
|
});
|
|
194
217
|
client.query('LISTEN "jobs:insert"');
|
|
195
218
|
client.on('error', (e: unknown) => {
|
|
219
|
+
if (this.stopped) {
|
|
220
|
+
release();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
196
223
|
log.error('Error with database notify listener', e);
|
|
197
224
|
if (e instanceof Error && e.stack) {
|
|
198
225
|
log.debug(e.stack);
|
|
199
226
|
}
|
|
200
227
|
release();
|
|
201
|
-
this.
|
|
228
|
+
if (!this.stopped) {
|
|
229
|
+
this.listen();
|
|
230
|
+
}
|
|
202
231
|
});
|
|
203
232
|
log.info(`${this.workerId} connected and looking for jobs...`);
|
|
204
233
|
this.doNext(client);
|
|
205
234
|
};
|
|
206
235
|
this.pgPool.connect(listenForChanges);
|
|
207
236
|
}
|
|
237
|
+
|
|
238
|
+
async stop(): Promise<void> {
|
|
239
|
+
this.stopped = true;
|
|
240
|
+
if (this.doNextTimer) {
|
|
241
|
+
clearTimeout(this.doNextTimer);
|
|
242
|
+
this.doNextTimer = undefined;
|
|
243
|
+
}
|
|
244
|
+
const client = this.listenClient;
|
|
245
|
+
const release = this.listenRelease;
|
|
246
|
+
this.listenClient = undefined;
|
|
247
|
+
this.listenRelease = undefined;
|
|
248
|
+
|
|
249
|
+
if (client && release) {
|
|
250
|
+
client.removeAllListeners('notification');
|
|
251
|
+
client.removeAllListeners('error');
|
|
252
|
+
try {
|
|
253
|
+
await client.query('UNLISTEN "jobs:insert"');
|
|
254
|
+
} catch {
|
|
255
|
+
// Ignore listener cleanup errors during shutdown.
|
|
256
|
+
}
|
|
257
|
+
release();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
208
260
|
}
|
|
209
261
|
|
|
210
262
|
export { Worker };
|