@lucaapp/service-utils 5.9.0 → 5.10.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/dist/lib/pgBoss/controller/routes.d.ts +6 -16
- package/dist/lib/pgBoss/controller/routes.js +34 -41
- package/dist/lib/pgBoss/helpers.d.ts +9 -1
- package/dist/lib/pgBoss/helpers.js +28 -1
- package/dist/lib/pgBoss/index.d.ts +17 -4
- package/dist/lib/pgBoss/index.js +29 -9
- package/dist/lib/pgBoss/service/manageJob.js +1 -1
- package/package.json +1 -1
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
import { Api } from '../../api/api';
|
|
2
2
|
import { PgBossService } from '../service';
|
|
3
|
+
import type { Middleware } from '../../api/types/middleware';
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* - GET /queues — list queues with stats
|
|
8
|
-
* - GET /queues/:name/jobs — list jobs in a queue
|
|
9
|
-
* - GET /queues/:queue/jobs/:id — job detail
|
|
10
|
-
* - POST /queues/:queue/jobs/:id/retry — retry a job
|
|
11
|
-
* - POST /queues/:queue/jobs/:id/cancel — cancel a job
|
|
12
|
-
* - DELETE /queues/:queue/jobs/:id — delete a job
|
|
13
|
-
* - GET /schedules — list cron schedules
|
|
14
|
-
* - POST /schedules — create a schedule
|
|
15
|
-
* - PUT /schedules/:name — update a schedule
|
|
16
|
-
* - DELETE /schedules/:name — delete a schedule
|
|
17
|
-
* - POST /queues/:name/jobs — enqueue a new job
|
|
18
|
-
* - GET /warnings — recent warnings
|
|
5
|
+
* Express path prefix for every pg-boss admin route. `Api.child()` only
|
|
6
|
+
* affects OpenAPI documentation, not the underlying express router, so the
|
|
7
|
+
* prefix MUST live on each path string to make routing work end-to-end.
|
|
19
8
|
*/
|
|
20
|
-
export declare const
|
|
9
|
+
export declare const PGBOSS_API_PATH_PREFIX = "/support/pgboss";
|
|
10
|
+
export declare const mountPgBossApiRoutes: (api: Api, service: PgBossService, middlewares?: Middleware<any, any, any, any, any, any>[]) => void;
|
|
@@ -1,37 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.mountPgBossApiRoutes = void 0;
|
|
3
|
+
exports.mountPgBossApiRoutes = exports.PGBOSS_API_PATH_PREFIX = void 0;
|
|
4
4
|
const send_1 = require("../../api/send");
|
|
5
5
|
const response_1 = require("../../api/response");
|
|
6
6
|
const routes_schema_1 = require("./routes.schema");
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - GET /queues — list queues with stats
|
|
12
|
-
* - GET /queues/:name/jobs — list jobs in a queue
|
|
13
|
-
* - GET /queues/:queue/jobs/:id — job detail
|
|
14
|
-
* - POST /queues/:queue/jobs/:id/retry — retry a job
|
|
15
|
-
* - POST /queues/:queue/jobs/:id/cancel — cancel a job
|
|
16
|
-
* - DELETE /queues/:queue/jobs/:id — delete a job
|
|
17
|
-
* - GET /schedules — list cron schedules
|
|
18
|
-
* - POST /schedules — create a schedule
|
|
19
|
-
* - PUT /schedules/:name — update a schedule
|
|
20
|
-
* - DELETE /schedules/:name — delete a schedule
|
|
21
|
-
* - POST /queues/:name/jobs — enqueue a new job
|
|
22
|
-
* - GET /warnings — recent warnings
|
|
8
|
+
* Express path prefix for every pg-boss admin route. `Api.child()` only
|
|
9
|
+
* affects OpenAPI documentation, not the underlying express router, so the
|
|
10
|
+
* prefix MUST live on each path string to make routing work end-to-end.
|
|
23
11
|
*/
|
|
24
|
-
|
|
12
|
+
exports.PGBOSS_API_PATH_PREFIX = '/support/pgboss';
|
|
13
|
+
const mountPgBossApiRoutes = (api, service,
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
+
middlewares) => {
|
|
25
16
|
const pgBossApi = api.child({ tags: ['PgBoss'] });
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
const p = (path) => `${exports.PGBOSS_API_PATH_PREFIX}${path}`;
|
|
18
|
+
const mw = middlewares?.length ? { middlewares } : {};
|
|
19
|
+
pgBossApi.get(p('/queues'), 'List all queues with stats', {
|
|
20
|
+
...mw,
|
|
28
21
|
responses: [(0, response_1.okResponse)(routes_schema_1.queueStatsArraySchema)],
|
|
29
22
|
}, async (_request, _context, respond) => {
|
|
30
23
|
const stats = await service.getQueueStats();
|
|
31
24
|
return respond((0, send_1.ok)(stats));
|
|
32
25
|
});
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
pgBossApi.get(p('/queues/:name/jobs'), 'List jobs in a queue', {
|
|
27
|
+
...mw,
|
|
35
28
|
responses: [(0, response_1.okResponse)(routes_schema_1.jobArraySchema)],
|
|
36
29
|
schemas: {
|
|
37
30
|
params: routes_schema_1.queueNameParamsSchema,
|
|
@@ -40,8 +33,8 @@ const mountPgBossApiRoutes = (api, service) => {
|
|
|
40
33
|
const jobs = await service.listJobs(request.params.name);
|
|
41
34
|
return respond((0, send_1.ok)(jobs));
|
|
42
35
|
});
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
pgBossApi.get(p('/queues/:queue/jobs/:id'), 'Get job details', {
|
|
37
|
+
...mw,
|
|
45
38
|
responses: [(0, response_1.okResponse)(routes_schema_1.jobDetailSchema)],
|
|
46
39
|
schemas: {
|
|
47
40
|
params: routes_schema_1.queueJobParamsSchema,
|
|
@@ -54,8 +47,8 @@ const mountPgBossApiRoutes = (api, service) => {
|
|
|
54
47
|
}
|
|
55
48
|
return respond((0, send_1.ok)(job));
|
|
56
49
|
});
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
pgBossApi.post(p('/queues/:queue/jobs/:id/retry'), 'Retry a failed job', {
|
|
51
|
+
...mw,
|
|
59
52
|
responses: [(0, response_1.okResponse)(routes_schema_1.successResponseSchema)],
|
|
60
53
|
schemas: {
|
|
61
54
|
params: routes_schema_1.queueJobParamsSchema,
|
|
@@ -65,8 +58,8 @@ const mountPgBossApiRoutes = (api, service) => {
|
|
|
65
58
|
await service.retryJob(queue, id);
|
|
66
59
|
return respond((0, send_1.ok)({ success: true, jobId: id }));
|
|
67
60
|
});
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
pgBossApi.post(p('/queues/:queue/jobs/:id/cancel'), 'Cancel a job', {
|
|
62
|
+
...mw,
|
|
70
63
|
responses: [(0, response_1.okResponse)(routes_schema_1.successResponseSchema)],
|
|
71
64
|
schemas: {
|
|
72
65
|
params: routes_schema_1.queueJobParamsSchema,
|
|
@@ -76,8 +69,8 @@ const mountPgBossApiRoutes = (api, service) => {
|
|
|
76
69
|
await service.cancelJob(queue, id);
|
|
77
70
|
return respond((0, send_1.ok)({ success: true, jobId: id }));
|
|
78
71
|
});
|
|
79
|
-
|
|
80
|
-
|
|
72
|
+
pgBossApi.delete(p('/queues/:queue/jobs/:id'), 'Delete a job', {
|
|
73
|
+
...mw,
|
|
81
74
|
responses: [(0, response_1.okResponse)(routes_schema_1.successResponseSchema)],
|
|
82
75
|
schemas: {
|
|
83
76
|
params: routes_schema_1.queueJobParamsSchema,
|
|
@@ -87,15 +80,15 @@ const mountPgBossApiRoutes = (api, service) => {
|
|
|
87
80
|
await service.deleteJob(queue, id);
|
|
88
81
|
return respond((0, send_1.ok)({ success: true, deleted: id }));
|
|
89
82
|
});
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
pgBossApi.get(p('/schedules'), 'List all cron schedules', {
|
|
84
|
+
...mw,
|
|
92
85
|
responses: [(0, response_1.okResponse)(routes_schema_1.scheduleArraySchema)],
|
|
93
86
|
}, async (_request, _context, respond) => {
|
|
94
87
|
const schedules = await service.getSchedules();
|
|
95
88
|
return respond((0, send_1.ok)(schedules));
|
|
96
89
|
});
|
|
97
|
-
|
|
98
|
-
|
|
90
|
+
pgBossApi.post(p('/schedules'), 'Create a cron schedule', {
|
|
91
|
+
...mw,
|
|
99
92
|
responses: [(0, response_1.createdResponse)(routes_schema_1.successResponseSchema)],
|
|
100
93
|
schemas: {
|
|
101
94
|
body: routes_schema_1.scheduleBodySchema,
|
|
@@ -105,8 +98,8 @@ const mountPgBossApiRoutes = (api, service) => {
|
|
|
105
98
|
await service.createSchedule(name, cron, data, options);
|
|
106
99
|
return respond((0, send_1.created)({ success: true, name }));
|
|
107
100
|
});
|
|
108
|
-
|
|
109
|
-
|
|
101
|
+
pgBossApi.put(p('/schedules/:name'), 'Update a cron schedule', {
|
|
102
|
+
...mw,
|
|
110
103
|
responses: [(0, response_1.okResponse)(routes_schema_1.successResponseSchema)],
|
|
111
104
|
schemas: {
|
|
112
105
|
params: routes_schema_1.scheduleNameParamsSchema,
|
|
@@ -117,8 +110,8 @@ const mountPgBossApiRoutes = (api, service) => {
|
|
|
117
110
|
await service.updateSchedule(request.params.name, cron, data, options);
|
|
118
111
|
return respond((0, send_1.ok)({ success: true, name: request.params.name }));
|
|
119
112
|
});
|
|
120
|
-
|
|
121
|
-
|
|
113
|
+
pgBossApi.delete(p('/schedules/:name'), 'Delete a cron schedule', {
|
|
114
|
+
...mw,
|
|
122
115
|
responses: [(0, response_1.okResponse)(routes_schema_1.successResponseSchema)],
|
|
123
116
|
schemas: {
|
|
124
117
|
params: routes_schema_1.scheduleNameParamsSchema,
|
|
@@ -127,8 +120,8 @@ const mountPgBossApiRoutes = (api, service) => {
|
|
|
127
120
|
await service.deleteSchedule(request.params.name);
|
|
128
121
|
return respond((0, send_1.ok)({ success: true, deleted: request.params.name }));
|
|
129
122
|
});
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
pgBossApi.post(p('/queues/:name/jobs'), 'Enqueue a new job', {
|
|
124
|
+
...mw,
|
|
132
125
|
responses: [(0, response_1.createdResponse)(routes_schema_1.successResponseSchema)],
|
|
133
126
|
schemas: {
|
|
134
127
|
params: routes_schema_1.queueNameParamsSchema,
|
|
@@ -139,8 +132,8 @@ const mountPgBossApiRoutes = (api, service) => {
|
|
|
139
132
|
const jobId = await service.enqueueJob(request.params.name, data, options);
|
|
140
133
|
return respond((0, send_1.created)({ success: true, jobId: jobId ?? undefined }));
|
|
141
134
|
});
|
|
142
|
-
|
|
143
|
-
|
|
135
|
+
pgBossApi.get(p('/warnings'), 'List recent warnings', {
|
|
136
|
+
...mw,
|
|
144
137
|
responses: [(0, response_1.okResponse)(routes_schema_1.warningArraySchema)],
|
|
145
138
|
schemas: {
|
|
146
139
|
query: routes_schema_1.warningsQuerySchema,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PgBoss } from 'pg-boss';
|
|
2
|
-
import type { SendOptions } from 'pg-boss';
|
|
2
|
+
import type { Job, SendOptions } from 'pg-boss';
|
|
3
3
|
import type { Logger } from 'pino';
|
|
4
4
|
import type { Sequelize, Transaction } from 'sequelize';
|
|
5
5
|
/**
|
|
@@ -13,3 +13,11 @@ export declare const enqueueJob: (boss: PgBoss, queueName: string, data: object,
|
|
|
13
13
|
* instead of calling internal SQL functions directly.
|
|
14
14
|
*/
|
|
15
15
|
export declare const enqueueInTransaction: (boss: PgBoss, queueName: string, data: object, options: SendOptions, transaction: Transaction, sequelize: Sequelize) => Promise<string | null>;
|
|
16
|
+
/**
|
|
17
|
+
* Wrap a pg-boss worker handler so that, when the final retry attempt fails,
|
|
18
|
+
* a Mattermost DLQ alert is fired before the error is re-thrown.
|
|
19
|
+
*
|
|
20
|
+
* Requires the worker to be registered with `{ includeMetadata: true }` so
|
|
21
|
+
* `retryCount` and `retryLimit` are populated on each job.
|
|
22
|
+
*/
|
|
23
|
+
export declare const withDlqAlerting: <T = object>(queueName: string, handler: (jobs: Job<T>[]) => Promise<void>, logger: Logger, mattermostWebhookUrl?: string) => ((jobs: Job<T>[]) => Promise<void>);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.enqueueInTransaction = exports.enqueueJob = void 0;
|
|
3
|
+
exports.withDlqAlerting = exports.enqueueInTransaction = exports.enqueueJob = void 0;
|
|
4
|
+
const metrics_1 = require("./metrics");
|
|
4
5
|
/**
|
|
5
6
|
* Enqueue a job via pg-boss with logging.
|
|
6
7
|
*/
|
|
@@ -42,3 +43,29 @@ const enqueueInTransaction = async (boss, queueName, data, options, transaction,
|
|
|
42
43
|
return boss.send(queueName, data, { ...options, db });
|
|
43
44
|
};
|
|
44
45
|
exports.enqueueInTransaction = enqueueInTransaction;
|
|
46
|
+
/**
|
|
47
|
+
* Wrap a pg-boss worker handler so that, when the final retry attempt fails,
|
|
48
|
+
* a Mattermost DLQ alert is fired before the error is re-thrown.
|
|
49
|
+
*
|
|
50
|
+
* Requires the worker to be registered with `{ includeMetadata: true }` so
|
|
51
|
+
* `retryCount` and `retryLimit` are populated on each job.
|
|
52
|
+
*/
|
|
53
|
+
const withDlqAlerting = (queueName, handler, logger, mattermostWebhookUrl) => {
|
|
54
|
+
return async (jobs) => {
|
|
55
|
+
try {
|
|
56
|
+
await handler(jobs);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
const job = jobs[0];
|
|
60
|
+
const retryCount = job?.retryCount ?? 0;
|
|
61
|
+
const retryLimit = job?.retryLimit ?? 0;
|
|
62
|
+
const isFinalFailure = retryLimit > 0 && retryCount >= retryLimit;
|
|
63
|
+
if (isFinalFailure && mattermostWebhookUrl && job) {
|
|
64
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
65
|
+
await (0, metrics_1.sendDlqAlert)(mattermostWebhookUrl, queueName, job.id, message, logger);
|
|
66
|
+
}
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
exports.withDlqAlerting = withDlqAlerting;
|
|
@@ -2,28 +2,41 @@ import { PgBoss } from 'pg-boss';
|
|
|
2
2
|
import type { Logger } from 'pino';
|
|
3
3
|
import type { PgBossConfig } from './types';
|
|
4
4
|
export { PgBoss };
|
|
5
|
+
export type { Job, SendOptions } from 'pg-boss';
|
|
5
6
|
export type { PgBossConfig, QueueDefinition, WorkerRegistration, PgBossInstance, } from './types';
|
|
6
7
|
export { PG_BOSS_DEFAULTS, buildPgBossDefaults } from './config';
|
|
7
8
|
export { mountPgBossApiRoutes } from './controller/routes';
|
|
8
9
|
export { PgBossService } from './service';
|
|
9
10
|
export { registerPgBossMetrics } from './metrics';
|
|
10
|
-
export { enqueueJob, enqueueInTransaction } from './helpers';
|
|
11
|
+
export { enqueueJob, enqueueInTransaction, withDlqAlerting } from './helpers';
|
|
11
12
|
export { sendDlqAlert } from './metrics';
|
|
12
13
|
export interface PgBossContext {
|
|
13
14
|
boss: PgBoss;
|
|
14
15
|
logger: Logger;
|
|
15
16
|
config: Required<PgBossConfig>;
|
|
17
|
+
serviceName: string;
|
|
18
|
+
metricsInterval?: NodeJS.Timeout;
|
|
16
19
|
}
|
|
17
20
|
/**
|
|
18
21
|
* Creates a pg-boss instance with error recovery (auto-restart on connection loss).
|
|
19
22
|
* Issue #510 mitigation: on error, waits 5s then restarts.
|
|
20
23
|
*/
|
|
21
|
-
export declare const createPgBoss: (config: PgBossConfig, logger: Logger) => PgBossContext;
|
|
24
|
+
export declare const createPgBoss: (config: PgBossConfig, logger: Logger, serviceName?: string) => PgBossContext;
|
|
22
25
|
/**
|
|
23
|
-
* Starts the pg-boss instance
|
|
26
|
+
* Starts the pg-boss instance and registers Prometheus metrics polling.
|
|
27
|
+
* Call after database is connected.
|
|
24
28
|
*/
|
|
25
29
|
export declare const startBoss: (ctx: PgBossContext) => Promise<void>;
|
|
26
30
|
/**
|
|
27
|
-
* Gracefully stops the pg-boss instance
|
|
31
|
+
* Gracefully stops the pg-boss instance and clears metrics polling.
|
|
32
|
+
* Suitable as a shutdown handler.
|
|
28
33
|
*/
|
|
29
34
|
export declare const stopBoss: (ctx: PgBossContext) => Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Maps the legacy `deleteAfterDays` setting to pg-boss v12's
|
|
37
|
+
* per-queue `deleteAfterSeconds` option. Use this when calling
|
|
38
|
+
* `boss.createQueue(name, { ...defaultRetention(ctx), policy: 'singleton' })`.
|
|
39
|
+
*/
|
|
40
|
+
export declare const defaultRetention: (ctx: PgBossContext) => {
|
|
41
|
+
deleteAfterSeconds: number;
|
|
42
|
+
};
|
package/dist/lib/pgBoss/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.stopBoss = exports.startBoss = exports.createPgBoss = exports.sendDlqAlert = exports.enqueueInTransaction = exports.enqueueJob = exports.registerPgBossMetrics = exports.PgBossService = exports.mountPgBossApiRoutes = exports.buildPgBossDefaults = exports.PG_BOSS_DEFAULTS = exports.PgBoss = void 0;
|
|
3
|
+
exports.defaultRetention = exports.stopBoss = exports.startBoss = exports.createPgBoss = exports.sendDlqAlert = exports.withDlqAlerting = exports.enqueueInTransaction = exports.enqueueJob = exports.registerPgBossMetrics = exports.PgBossService = exports.mountPgBossApiRoutes = exports.buildPgBossDefaults = exports.PG_BOSS_DEFAULTS = exports.PgBoss = void 0;
|
|
4
4
|
const pg_boss_1 = require("pg-boss");
|
|
5
5
|
Object.defineProperty(exports, "PgBoss", { enumerable: true, get: function () { return pg_boss_1.PgBoss; } });
|
|
6
6
|
const config_1 = require("./config");
|
|
7
|
+
const metrics_1 = require("./metrics");
|
|
7
8
|
var config_2 = require("./config");
|
|
8
9
|
Object.defineProperty(exports, "PG_BOSS_DEFAULTS", { enumerable: true, get: function () { return config_2.PG_BOSS_DEFAULTS; } });
|
|
9
10
|
Object.defineProperty(exports, "buildPgBossDefaults", { enumerable: true, get: function () { return config_2.buildPgBossDefaults; } });
|
|
@@ -11,24 +12,27 @@ var routes_1 = require("./controller/routes");
|
|
|
11
12
|
Object.defineProperty(exports, "mountPgBossApiRoutes", { enumerable: true, get: function () { return routes_1.mountPgBossApiRoutes; } });
|
|
12
13
|
var service_1 = require("./service");
|
|
13
14
|
Object.defineProperty(exports, "PgBossService", { enumerable: true, get: function () { return service_1.PgBossService; } });
|
|
14
|
-
var
|
|
15
|
-
Object.defineProperty(exports, "registerPgBossMetrics", { enumerable: true, get: function () { return
|
|
15
|
+
var metrics_2 = require("./metrics");
|
|
16
|
+
Object.defineProperty(exports, "registerPgBossMetrics", { enumerable: true, get: function () { return metrics_2.registerPgBossMetrics; } });
|
|
16
17
|
var helpers_1 = require("./helpers");
|
|
17
18
|
Object.defineProperty(exports, "enqueueJob", { enumerable: true, get: function () { return helpers_1.enqueueJob; } });
|
|
18
19
|
Object.defineProperty(exports, "enqueueInTransaction", { enumerable: true, get: function () { return helpers_1.enqueueInTransaction; } });
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
Object.defineProperty(exports, "withDlqAlerting", { enumerable: true, get: function () { return helpers_1.withDlqAlerting; } });
|
|
21
|
+
var metrics_3 = require("./metrics");
|
|
22
|
+
Object.defineProperty(exports, "sendDlqAlert", { enumerable: true, get: function () { return metrics_3.sendDlqAlert; } });
|
|
21
23
|
const RESTART_DELAY_MS = 5000;
|
|
24
|
+
const SECONDS_PER_DAY = 86_400;
|
|
22
25
|
/**
|
|
23
26
|
* Creates a pg-boss instance with error recovery (auto-restart on connection loss).
|
|
24
27
|
* Issue #510 mitigation: on error, waits 5s then restarts.
|
|
25
28
|
*/
|
|
26
|
-
const createPgBoss = (config, logger) => {
|
|
29
|
+
const createPgBoss = (config, logger, serviceName = config.schema) => {
|
|
27
30
|
const resolvedConfig = (0, config_1.buildPgBossDefaults)(config);
|
|
28
31
|
const boss = new pg_boss_1.PgBoss({
|
|
29
32
|
connectionString: resolvedConfig.connectionString,
|
|
30
33
|
schema: resolvedConfig.schema,
|
|
31
34
|
application_name: resolvedConfig.applicationName,
|
|
35
|
+
max: resolvedConfig.maxConnectionPoolSize,
|
|
32
36
|
migrate: true,
|
|
33
37
|
});
|
|
34
38
|
boss.on('error', (error) => {
|
|
@@ -38,27 +42,43 @@ const createPgBoss = (config, logger) => {
|
|
|
38
42
|
boss.on('warning', warning => {
|
|
39
43
|
logger.warn({ warning }, 'pg-boss warning');
|
|
40
44
|
});
|
|
41
|
-
return { boss, logger, config: resolvedConfig };
|
|
45
|
+
return { boss, logger, config: resolvedConfig, serviceName };
|
|
42
46
|
};
|
|
43
47
|
exports.createPgBoss = createPgBoss;
|
|
44
48
|
/**
|
|
45
|
-
* Starts the pg-boss instance
|
|
49
|
+
* Starts the pg-boss instance and registers Prometheus metrics polling.
|
|
50
|
+
* Call after database is connected.
|
|
46
51
|
*/
|
|
47
52
|
const startBoss = async (ctx) => {
|
|
48
53
|
ctx.logger.info({ schema: ctx.config.schema }, 'Starting pg-boss');
|
|
49
54
|
await ctx.boss.start();
|
|
55
|
+
ctx.metricsInterval = (0, metrics_1.registerPgBossMetrics)(ctx.boss, ctx.serviceName, ctx.logger, ctx.config.mattermostWebhookUrl || undefined);
|
|
50
56
|
ctx.logger.info({ schema: ctx.config.schema }, 'pg-boss started successfully');
|
|
51
57
|
};
|
|
52
58
|
exports.startBoss = startBoss;
|
|
53
59
|
/**
|
|
54
|
-
* Gracefully stops the pg-boss instance
|
|
60
|
+
* Gracefully stops the pg-boss instance and clears metrics polling.
|
|
61
|
+
* Suitable as a shutdown handler.
|
|
55
62
|
*/
|
|
56
63
|
const stopBoss = async (ctx) => {
|
|
57
64
|
ctx.logger.info({ schema: ctx.config.schema }, 'Stopping pg-boss');
|
|
65
|
+
if (ctx.metricsInterval) {
|
|
66
|
+
clearInterval(ctx.metricsInterval);
|
|
67
|
+
ctx.metricsInterval = undefined;
|
|
68
|
+
}
|
|
58
69
|
await ctx.boss.stop({ graceful: true, timeout: 30_000 });
|
|
59
70
|
ctx.logger.info({ schema: ctx.config.schema }, 'pg-boss stopped');
|
|
60
71
|
};
|
|
61
72
|
exports.stopBoss = stopBoss;
|
|
73
|
+
/**
|
|
74
|
+
* Maps the legacy `deleteAfterDays` setting to pg-boss v12's
|
|
75
|
+
* per-queue `deleteAfterSeconds` option. Use this when calling
|
|
76
|
+
* `boss.createQueue(name, { ...defaultRetention(ctx), policy: 'singleton' })`.
|
|
77
|
+
*/
|
|
78
|
+
const defaultRetention = (ctx) => ({
|
|
79
|
+
deleteAfterSeconds: ctx.config.deleteAfterDays * SECONDS_PER_DAY,
|
|
80
|
+
});
|
|
81
|
+
exports.defaultRetention = defaultRetention;
|
|
62
82
|
const scheduleRestart = (boss, logger) => {
|
|
63
83
|
setTimeout(async () => {
|
|
64
84
|
try {
|
|
@@ -4,7 +4,7 @@ exports.manageJob = void 0;
|
|
|
4
4
|
const manageJob = async (boss, logger, action, queueName, jobId) => {
|
|
5
5
|
switch (action) {
|
|
6
6
|
case 'retry':
|
|
7
|
-
await boss.
|
|
7
|
+
await boss.retry(queueName, jobId);
|
|
8
8
|
break;
|
|
9
9
|
case 'cancel':
|
|
10
10
|
await boss.cancel(queueName, jobId);
|