@lavoro/postgres 0.3.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/build/index.d.ts +36 -0
- package/build/index.js +315 -0
- package/build/index.js.map +1 -0
- package/package.json +52 -0
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { QueueDriver, QueueConfig, WorkerOptions, QueueName, QueueDriverStopOptions, Job, Payload, ConfiguredDriver } from '@lavoro/core';
|
|
2
|
+
import { LockFactory } from '@verrou/core';
|
|
3
|
+
|
|
4
|
+
type PostgresConfig = {
|
|
5
|
+
host: string;
|
|
6
|
+
port: string | number;
|
|
7
|
+
user: string;
|
|
8
|
+
password: string;
|
|
9
|
+
database: string;
|
|
10
|
+
};
|
|
11
|
+
declare class PostgresQueueDriver extends QueueDriver<PostgresConfig> {
|
|
12
|
+
private boss;
|
|
13
|
+
private lockFactory?;
|
|
14
|
+
private lockKnexInstance?;
|
|
15
|
+
private lockTableName;
|
|
16
|
+
constructor(queueConfig: QueueConfig, options: Record<string, WorkerOptions>, config?: PostgresConfig);
|
|
17
|
+
createLockProvider(): LockFactory;
|
|
18
|
+
destroyLockProvider(): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @param fullyQualifiedJobName
|
|
22
|
+
*/
|
|
23
|
+
private createWorker;
|
|
24
|
+
private processJob;
|
|
25
|
+
listen(queue: QueueName, options?: WorkerOptions): Promise<void>;
|
|
26
|
+
start(): Promise<void>;
|
|
27
|
+
stop(options?: QueueDriverStopOptions): Promise<void>;
|
|
28
|
+
enqueue<T extends Job, P extends Payload<T>>(job: T, payload: P): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Builder function for PostgresQueueDriver.
|
|
32
|
+
* Creates a driver descriptor with type-safe config.
|
|
33
|
+
*/
|
|
34
|
+
declare function postgres(config: PostgresConfig): ConfiguredDriver<PostgresQueueDriver, PostgresConfig>;
|
|
35
|
+
|
|
36
|
+
export { type PostgresConfig, PostgresQueueDriver, postgres };
|
package/build/index.js
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
3
|
+
var __reflectGet = Reflect.get;
|
|
4
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
+
var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
|
|
7
|
+
var __async = (__this, __arguments, generator) => {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
var fulfilled = (value) => {
|
|
10
|
+
try {
|
|
11
|
+
step(generator.next(value));
|
|
12
|
+
} catch (e) {
|
|
13
|
+
reject(e);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var rejected = (value) => {
|
|
17
|
+
try {
|
|
18
|
+
step(generator.throw(value));
|
|
19
|
+
} catch (e) {
|
|
20
|
+
reject(e);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
24
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// src/index.ts
|
|
29
|
+
import {
|
|
30
|
+
Job,
|
|
31
|
+
QueueDriver
|
|
32
|
+
} from "@lavoro/core";
|
|
33
|
+
import { LockFactory } from "@verrou/core";
|
|
34
|
+
import { knexStore } from "@verrou/core/drivers/knex";
|
|
35
|
+
import knex from "knex";
|
|
36
|
+
import { PgBoss } from "pg-boss";
|
|
37
|
+
var PostgresQueueDriver = class _PostgresQueueDriver extends QueueDriver {
|
|
38
|
+
constructor(queueConfig, options, config) {
|
|
39
|
+
if (!config) {
|
|
40
|
+
throw new Error("PostgresQueueDriver requires a config object");
|
|
41
|
+
}
|
|
42
|
+
super(queueConfig, options, config);
|
|
43
|
+
__publicField(this, "boss");
|
|
44
|
+
__publicField(this, "lockFactory");
|
|
45
|
+
__publicField(this, "lockKnexInstance");
|
|
46
|
+
__publicField(this, "lockTableName", "lavoro_locks");
|
|
47
|
+
this.boss = new PgBoss({
|
|
48
|
+
connectionString: `postgresql://${config.user}:${config.password}@${config.host}:${config.port}/${config.database}`
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
createLockProvider() {
|
|
52
|
+
const knexInstance = knex({
|
|
53
|
+
client: "pg",
|
|
54
|
+
connection: {
|
|
55
|
+
host: this.driverConfig.host,
|
|
56
|
+
port: Number(this.driverConfig.port),
|
|
57
|
+
user: this.driverConfig.user,
|
|
58
|
+
password: this.driverConfig.password,
|
|
59
|
+
database: this.driverConfig.database
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
this.lockKnexInstance = knexInstance;
|
|
63
|
+
this.lockFactory = new LockFactory(
|
|
64
|
+
knexStore({
|
|
65
|
+
connection: this.lockKnexInstance,
|
|
66
|
+
autoCreateTable: true,
|
|
67
|
+
tableName: this.lockTableName
|
|
68
|
+
}).factory()
|
|
69
|
+
);
|
|
70
|
+
return this.lockFactory;
|
|
71
|
+
}
|
|
72
|
+
destroyLockProvider() {
|
|
73
|
+
return __async(this, null, function* () {
|
|
74
|
+
if (this.lockKnexInstance) {
|
|
75
|
+
yield this.lockKnexInstance.destroy();
|
|
76
|
+
this.lockKnexInstance = void 0;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
*
|
|
82
|
+
* @param fullyQualifiedJobName
|
|
83
|
+
*/
|
|
84
|
+
createWorker(fullyQualifiedJobName, options) {
|
|
85
|
+
return __async(this, null, function* () {
|
|
86
|
+
var _a;
|
|
87
|
+
const { concurrency = 1 } = options;
|
|
88
|
+
const { queue, name } = Job.parseName(fullyQualifiedJobName);
|
|
89
|
+
yield this.boss.createQueue(fullyQualifiedJobName, {
|
|
90
|
+
// partition: true,
|
|
91
|
+
// deadLetter: undefined,
|
|
92
|
+
// retryLimit: 3,
|
|
93
|
+
// retryDelay: 1,
|
|
94
|
+
// retryBackoff: true,
|
|
95
|
+
// retentionSeconds: 0, // Default: 14 days. How many seconds a job may be in created or retry state before it's deleted.
|
|
96
|
+
// deleteAfterSeconds: 0, // Default: 7 days. How long a job should be retained in the database after it's completed.
|
|
97
|
+
});
|
|
98
|
+
if (!((_a = this.config) == null ? void 0 : _a.worker) || concurrency === 0) {
|
|
99
|
+
this.logger.trace(
|
|
100
|
+
{ connection: this.connection, queue, job: name },
|
|
101
|
+
"Queue worker is disabled - skipping"
|
|
102
|
+
);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
yield this.boss.work(
|
|
106
|
+
fullyQualifiedJobName,
|
|
107
|
+
{
|
|
108
|
+
batchSize: concurrency
|
|
109
|
+
// pollingIntervalSeconds: 2, // 2 seconds by default
|
|
110
|
+
},
|
|
111
|
+
(jobs) => __async(this, null, function* () {
|
|
112
|
+
Promise.allSettled(
|
|
113
|
+
jobs.map((job) => __async(this, null, function* () {
|
|
114
|
+
try {
|
|
115
|
+
yield this.processJob(job);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
this.logger.warn(
|
|
118
|
+
{
|
|
119
|
+
connection: this.connection,
|
|
120
|
+
queue,
|
|
121
|
+
job: job.name,
|
|
122
|
+
err: error
|
|
123
|
+
},
|
|
124
|
+
"Job failed"
|
|
125
|
+
);
|
|
126
|
+
yield this.boss.fail(job.name, job.id, error);
|
|
127
|
+
}
|
|
128
|
+
}))
|
|
129
|
+
);
|
|
130
|
+
})
|
|
131
|
+
);
|
|
132
|
+
this.logger.trace(
|
|
133
|
+
{
|
|
134
|
+
connection: this.connection,
|
|
135
|
+
queue,
|
|
136
|
+
job: name,
|
|
137
|
+
options
|
|
138
|
+
},
|
|
139
|
+
"Started worker"
|
|
140
|
+
);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
processJob(job) {
|
|
144
|
+
return __async(this, null, function* () {
|
|
145
|
+
var _a;
|
|
146
|
+
const { queue, name } = Job.parseName(job.name);
|
|
147
|
+
if (!queue || !name) {
|
|
148
|
+
const error = new Error(`Invalid job class name: ${job.name}`);
|
|
149
|
+
this.logger.warn(error);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
this.logger.trace({ job: name }, "Processing job");
|
|
153
|
+
try {
|
|
154
|
+
this.checkIfJobIsRegistered(name);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
this.logger.warn(error.message);
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
const jobClass = this.registeredJobs.get(name);
|
|
160
|
+
if (!jobClass) {
|
|
161
|
+
const error = new Error(`Job is not registered: ${name}`);
|
|
162
|
+
this.logger.warn(error);
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
const jobInstance = new jobClass();
|
|
166
|
+
jobInstance.connection = this.connection;
|
|
167
|
+
jobInstance.queue = queue;
|
|
168
|
+
jobInstance.id = job.id;
|
|
169
|
+
this.logger.debug(
|
|
170
|
+
{
|
|
171
|
+
connection: this.connection,
|
|
172
|
+
queue,
|
|
173
|
+
job: name,
|
|
174
|
+
id: job.id
|
|
175
|
+
},
|
|
176
|
+
"Processing job"
|
|
177
|
+
);
|
|
178
|
+
const serializedLock = (_a = job.data) == null ? void 0 : _a._lock;
|
|
179
|
+
let lock;
|
|
180
|
+
if (serializedLock !== void 0 && this.lockFactory !== void 0) {
|
|
181
|
+
try {
|
|
182
|
+
lock = this.lockFactory.restoreLock(serializedLock);
|
|
183
|
+
yield lock.acquireImmediately();
|
|
184
|
+
this.logger.trace(
|
|
185
|
+
{ job: name, id: job.id, lock: serializedLock },
|
|
186
|
+
"Restored lock from scheduler"
|
|
187
|
+
);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
this.logger.warn(
|
|
190
|
+
{ job: name, id: job.id, error },
|
|
191
|
+
"Failed to restore lock"
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
yield jobInstance.handle(job.data);
|
|
197
|
+
} finally {
|
|
198
|
+
if (lock) {
|
|
199
|
+
try {
|
|
200
|
+
yield lock.forceRelease();
|
|
201
|
+
this.logger.trace(
|
|
202
|
+
{ job: name, id: job.id, lock: lock.serialize() },
|
|
203
|
+
"Released lock for scheduled job"
|
|
204
|
+
);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
this.logger.warn(
|
|
207
|
+
{ job: name, id: job.id, error },
|
|
208
|
+
"Failed to release lock"
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
this.logger.trace(
|
|
214
|
+
{
|
|
215
|
+
connection: this.connection,
|
|
216
|
+
queue,
|
|
217
|
+
job: name,
|
|
218
|
+
id: job.id
|
|
219
|
+
},
|
|
220
|
+
"Job completed"
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
listen(queue, options) {
|
|
225
|
+
return __async(this, null, function* () {
|
|
226
|
+
const mergedOptions = this.getMergedWorkerOptions(queue, options);
|
|
227
|
+
yield __superGet(_PostgresQueueDriver.prototype, this, "listen").call(this, queue, options);
|
|
228
|
+
for (const job of this.registeredJobs.values()) {
|
|
229
|
+
yield this.createWorker(Job.compileName(queue, job.name), mergedOptions);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
start() {
|
|
234
|
+
return __async(this, null, function* () {
|
|
235
|
+
this.boss.on("error", (error) => __async(this, null, function* () {
|
|
236
|
+
this.logger.error({ error }, "Error in Postgres queue driver");
|
|
237
|
+
yield this.stop({ graceful: false });
|
|
238
|
+
}));
|
|
239
|
+
yield this.boss.start();
|
|
240
|
+
yield __superGet(_PostgresQueueDriver.prototype, this, "start").call(this);
|
|
241
|
+
this.logger.trace(
|
|
242
|
+
{ connection: this.connection, driver: "postgres" },
|
|
243
|
+
"Queue driver started"
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
stop(options) {
|
|
248
|
+
return __async(this, null, function* () {
|
|
249
|
+
const { graceful = true, timeout = 3e4 } = options || {};
|
|
250
|
+
this.logger.trace(
|
|
251
|
+
{ connection: this.connection, driver: "postgres", graceful, timeout },
|
|
252
|
+
`Waiting for pg-boss to stop...`
|
|
253
|
+
);
|
|
254
|
+
yield this.boss.stop({ graceful, timeout });
|
|
255
|
+
this.logger.trace(
|
|
256
|
+
{ connection: this.connection, driver: "postgres" },
|
|
257
|
+
"Pg-boss stopped"
|
|
258
|
+
);
|
|
259
|
+
yield __superGet(_PostgresQueueDriver.prototype, this, "stop").call(this);
|
|
260
|
+
this.logger.trace(
|
|
261
|
+
{ connection: this.connection, driver: "postgres" },
|
|
262
|
+
"Queue driver stopped"
|
|
263
|
+
);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
enqueue(job, payload) {
|
|
267
|
+
return __async(this, null, function* () {
|
|
268
|
+
yield __superGet(_PostgresQueueDriver.prototype, this, "enqueue").call(this, job, payload);
|
|
269
|
+
this.logger.trace(
|
|
270
|
+
{
|
|
271
|
+
connection: this.connection,
|
|
272
|
+
queue: job.options.queue,
|
|
273
|
+
job: job.name
|
|
274
|
+
},
|
|
275
|
+
"Enqueuing job"
|
|
276
|
+
);
|
|
277
|
+
yield this.boss.send(job.fullyQualifiedName, payload, {
|
|
278
|
+
// priority: 2,
|
|
279
|
+
// retryLimit: 3,
|
|
280
|
+
// startAfter: 10,
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
// public async schedule<T extends Job, P extends Payload<T>>(
|
|
285
|
+
// job: T,
|
|
286
|
+
// payload: P,
|
|
287
|
+
// ): Promise<void> {
|
|
288
|
+
// await super.schedule(job, payload)
|
|
289
|
+
// this.logger.trace(
|
|
290
|
+
// { connection: this.connection, queue: job.options.queue, job: job.name },
|
|
291
|
+
// 'Scheduling job',
|
|
292
|
+
// )
|
|
293
|
+
// const scheduleExpression = job.options.schedule || '* * * * *' // every second
|
|
294
|
+
// await this.boss.schedule(
|
|
295
|
+
// job.fullyQualifiedName,
|
|
296
|
+
// scheduleExpression,
|
|
297
|
+
// payload as object,
|
|
298
|
+
// {
|
|
299
|
+
// // tz: 'UTC',
|
|
300
|
+
// // key: 'unique_key',
|
|
301
|
+
// },
|
|
302
|
+
// )
|
|
303
|
+
// }
|
|
304
|
+
};
|
|
305
|
+
function postgres(config) {
|
|
306
|
+
return {
|
|
307
|
+
constructor: PostgresQueueDriver,
|
|
308
|
+
config
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
export {
|
|
312
|
+
PostgresQueueDriver,
|
|
313
|
+
postgres
|
|
314
|
+
};
|
|
315
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n Job,\n Payload,\n QueueDriver,\n QueueDriverStopOptions,\n QueueName,\n ConfiguredDriver,\n QueueConfig,\n WorkerOptions,\n} from '@lavoro/core'\n\nimport { Lock, LockFactory } from '@verrou/core'\nimport { knexStore } from '@verrou/core/drivers/knex'\nimport type { SerializedLock } from '@verrou/core/types'\nimport knex from 'knex'\nimport { PgBoss, Job as PgBossJob } from 'pg-boss'\n\nexport type PostgresConfig = {\n host: string\n port: string | number\n user: string\n password: string\n database: string\n}\n\nexport class PostgresQueueDriver extends QueueDriver<PostgresConfig> {\n private boss: PgBoss\n private lockFactory?: LockFactory\n private lockKnexInstance?: ReturnType<typeof knex>\n private lockTableName: string = 'lavoro_locks'\n\n constructor(\n queueConfig: QueueConfig,\n options: Record<string, WorkerOptions>,\n config?: PostgresConfig,\n ) {\n /**\n * Since the config is marked optional and it is required for this driver,\n * we check it during runtime before creating the driver.\n */\n if (!config) {\n throw new Error('PostgresQueueDriver requires a config object')\n }\n\n super(queueConfig, options, config)\n\n this.boss = new PgBoss({\n connectionString: `postgresql://${config.user}:${config.password}@${config.host}:${config.port}/${config.database}`,\n })\n }\n\n public createLockProvider() {\n const knexInstance = knex({\n client: 'pg',\n connection: {\n host: this.driverConfig.host,\n port: Number(this.driverConfig.port),\n user: this.driverConfig.user,\n password: this.driverConfig.password,\n database: this.driverConfig.database,\n },\n })\n\n this.lockKnexInstance = knexInstance\n\n this.lockFactory = new LockFactory(\n knexStore({\n connection: this.lockKnexInstance,\n autoCreateTable: true,\n tableName: this.lockTableName,\n }).factory(),\n )\n\n return this.lockFactory\n }\n\n public async destroyLockProvider(): Promise<void> {\n if (this.lockKnexInstance) {\n await this.lockKnexInstance.destroy()\n this.lockKnexInstance = undefined\n }\n }\n\n /**\n *\n * @param fullyQualifiedJobName\n */\n private async createWorker(\n fullyQualifiedJobName: string,\n options: WorkerOptions,\n ): Promise<void> {\n const { concurrency = 1 } = options\n\n const { queue, name } = Job.parseName(fullyQualifiedJobName)\n\n await this.boss.createQueue(fullyQualifiedJobName, {\n // partition: true,\n // deadLetter: undefined,\n // retryLimit: 3,\n // retryDelay: 1,\n // retryBackoff: true,\n // retentionSeconds: 0, // Default: 14 days. How many seconds a job may be in created or retry state before it's deleted.\n // deleteAfterSeconds: 0, // Default: 7 days. How long a job should be retained in the database after it's completed.\n })\n\n if (!this.config?.worker || concurrency === 0) {\n this.logger.trace(\n { connection: this.connection, queue, job: name },\n 'Queue worker is disabled - skipping',\n )\n\n return\n }\n\n await this.boss.work(\n fullyQualifiedJobName,\n {\n batchSize: concurrency,\n // pollingIntervalSeconds: 2, // 2 seconds by default\n },\n async (jobs) => {\n Promise.allSettled(\n jobs.map(async (job) => {\n try {\n await this.processJob(job)\n } catch (error) {\n // TODO: Add a way to signal about the error\n this.logger.warn(\n {\n connection: this.connection,\n queue,\n job: job.name,\n err: error,\n },\n 'Job failed',\n )\n\n await this.boss.fail(job.name, job.id, error)\n }\n }),\n )\n },\n )\n\n this.logger.trace(\n {\n connection: this.connection,\n queue,\n job: name,\n options,\n },\n 'Started worker',\n )\n }\n\n private async processJob(job: PgBossJob<unknown>): Promise<void> {\n const { queue, name } = Job.parseName(job.name)\n\n if (!queue || !name) {\n const error = new Error(`Invalid job class name: ${job.name}`)\n this.logger.warn(error)\n throw error\n }\n\n this.logger.trace({ job: name }, 'Processing job')\n\n try {\n this.checkIfJobIsRegistered(name)\n } catch (error) {\n this.logger.warn(error.message)\n throw error\n }\n\n const jobClass = this.registeredJobs.get(name)\n\n if (!jobClass) {\n const error = new Error(`Job is not registered: ${name}`)\n this.logger.warn(error)\n throw error\n }\n\n const jobInstance = new jobClass()\n\n jobInstance.connection = this.connection\n jobInstance.queue = queue\n jobInstance.id = job.id\n\n // TODO: Make this pretty\n\n this.logger.debug(\n {\n connection: this.connection,\n queue,\n job: name,\n id: job.id,\n },\n 'Processing job',\n )\n\n /**\n * A job might have been scheduled by the scheduler,\n * in which case we need to restore the lock from the payload.\n *\n * This will prevent the job from being scheduled\n * while it is being processed.\n */\n const serializedLock = (job.data as any)?._lock as\n | SerializedLock\n | undefined\n\n let lock: Lock | undefined\n\n if (serializedLock !== undefined && this.lockFactory !== undefined) {\n try {\n lock = this.lockFactory.restoreLock(serializedLock)\n await lock.acquireImmediately()\n\n this.logger.trace(\n { job: name, id: job.id, lock: serializedLock },\n 'Restored lock from scheduler',\n )\n } catch (error) {\n this.logger.warn(\n { job: name, id: job.id, error },\n 'Failed to restore lock',\n )\n }\n }\n\n /**\n * Next, we process the actual job.\n */\n try {\n await jobInstance.handle(job.data)\n } finally {\n /**\n * If we previously acquired a lock for\n * this job, we need to release it here.\n */\n if (lock) {\n try {\n await lock.forceRelease()\n\n this.logger.trace(\n { job: name, id: job.id, lock: lock.serialize() },\n 'Released lock for scheduled job',\n )\n } catch (error) {\n this.logger.warn(\n { job: name, id: job.id, error },\n 'Failed to release lock',\n )\n }\n }\n }\n\n this.logger.trace(\n {\n connection: this.connection,\n queue,\n job: name,\n id: job.id,\n },\n 'Job completed',\n )\n }\n\n public async listen(\n queue: QueueName,\n options?: WorkerOptions,\n ): Promise<void> {\n const mergedOptions = this.getMergedWorkerOptions(queue, options)\n await super.listen(queue, options)\n for (const job of this.registeredJobs.values()) {\n await this.createWorker(Job.compileName(queue, job.name), mergedOptions)\n }\n }\n\n public async start(): Promise<void> {\n // TODO: Add error handling\n this.boss.on('error', async (error) => {\n this.logger.error({ error }, 'Error in Postgres queue driver')\n await this.stop({ graceful: false })\n })\n\n await this.boss.start()\n\n await super.start()\n\n this.logger.trace(\n { connection: this.connection, driver: 'postgres' },\n 'Queue driver started',\n )\n }\n\n public async stop(options?: QueueDriverStopOptions): Promise<void> {\n const { graceful = true, timeout = 30000 } = options || {}\n\n this.logger.trace(\n { connection: this.connection, driver: 'postgres', graceful, timeout },\n `Waiting for pg-boss to stop...`,\n )\n\n await this.boss.stop({ graceful, timeout })\n\n this.logger.trace(\n { connection: this.connection, driver: 'postgres' },\n 'Pg-boss stopped',\n )\n\n await super.stop()\n\n this.logger.trace(\n { connection: this.connection, driver: 'postgres' },\n 'Queue driver stopped',\n )\n }\n\n public async enqueue<T extends Job, P extends Payload<T>>(\n job: T,\n payload: P,\n ): Promise<void> {\n await super.enqueue(job, payload)\n\n this.logger.trace(\n {\n connection: this.connection,\n queue: job.options.queue,\n job: job.name,\n },\n 'Enqueuing job',\n )\n\n await this.boss.send(job.fullyQualifiedName, payload as object, {\n // priority: 2,\n // retryLimit: 3,\n // startAfter: 10,\n })\n }\n\n // public async schedule<T extends Job, P extends Payload<T>>(\n // job: T,\n // payload: P,\n // ): Promise<void> {\n // await super.schedule(job, payload)\n\n // this.logger.trace(\n // { connection: this.connection, queue: job.options.queue, job: job.name },\n // 'Scheduling job',\n // )\n\n // const scheduleExpression = job.options.schedule || '* * * * *' // every second\n\n // await this.boss.schedule(\n // job.fullyQualifiedName,\n // scheduleExpression,\n // payload as object,\n // {\n // // tz: 'UTC',\n // // key: 'unique_key',\n // },\n // )\n // }\n}\n\n/**\n * Builder function for PostgresQueueDriver.\n * Creates a driver descriptor with type-safe config.\n */\nexport function postgres(\n config: PostgresConfig,\n): ConfiguredDriver<PostgresQueueDriver, PostgresConfig> {\n return {\n constructor: PostgresQueueDriver,\n config: config,\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lavoro/postgres",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "PostgreSQL queue driver for Lavoro with support for distributed locking",
|
|
6
|
+
"author": "Aleksei Ivanov <contact@aleksei.dev>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/lexuzieel/lavoro.git",
|
|
14
|
+
"directory": "packages/postgres"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/lexuzieel/lavoro#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/lexuzieel/lavoro/issues"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"queue",
|
|
22
|
+
"postgres",
|
|
23
|
+
"postgresql",
|
|
24
|
+
"pg-boss",
|
|
25
|
+
"lavoro",
|
|
26
|
+
"driver"
|
|
27
|
+
],
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./build/index.d.ts",
|
|
31
|
+
"import": "./build/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"main": "build/index.js",
|
|
35
|
+
"files": [
|
|
36
|
+
"build"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"check": "tsc --noEmit",
|
|
40
|
+
"build": "tsup-node",
|
|
41
|
+
"watch": "tsup-node --watch"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@lavoro/core": "*",
|
|
45
|
+
"@verrou/core": "^0.5.2"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"knex": "^3.1.0",
|
|
49
|
+
"pg": "^8.16.3",
|
|
50
|
+
"pg-boss": "^12.2.0"
|
|
51
|
+
}
|
|
52
|
+
}
|