@agendajs/postgres-backend 1.0.0-alpha.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.
@@ -0,0 +1,559 @@
1
+ import debug from 'debug';
2
+ import { Pool } from 'pg';
3
+ import { toJobId, computeJobState } from 'agenda';
4
+ import { getCreateTableSQL, getCreateIndexesSQL, getUpdateTimestampTriggerSQL } from './schema.js';
5
+ const log = debug('agenda:postgres:repository');
6
+ /**
7
+ * PostgreSQL implementation of JobRepository
8
+ */
9
+ export class PostgresJobRepository {
10
+ config;
11
+ pool;
12
+ ownPool;
13
+ tableName;
14
+ ensureSchema;
15
+ sort;
16
+ disconnected = false;
17
+ constructor(config) {
18
+ this.config = config;
19
+ this.tableName = config.tableName || 'agenda_jobs';
20
+ this.ensureSchema = config.ensureSchema ?? true;
21
+ this.sort = config.sort || { nextRunAt: 'asc', priority: 'desc' };
22
+ // Use existing pool or create a new one
23
+ if (config.pool) {
24
+ // Use existing pool (won't be closed on disconnect)
25
+ this.pool = config.pool;
26
+ this.ownPool = false;
27
+ }
28
+ else if (config.connectionString || config.poolConfig) {
29
+ this.ownPool = true;
30
+ this.createPool();
31
+ }
32
+ else {
33
+ throw new Error('PostgresBackend requires pool, connectionString, or poolConfig');
34
+ }
35
+ }
36
+ createPool() {
37
+ if (this.config.connectionString) {
38
+ this.pool = new Pool({ connectionString: this.config.connectionString });
39
+ }
40
+ else if (this.config.poolConfig) {
41
+ this.pool = new Pool(this.config.poolConfig);
42
+ }
43
+ this.disconnected = false;
44
+ }
45
+ /**
46
+ * Get the underlying pool (for use by notification channel)
47
+ */
48
+ getPool() {
49
+ return this.pool;
50
+ }
51
+ async connect() {
52
+ log('connecting to PostgreSQL');
53
+ // Recreate pool if it was disconnected
54
+ if (this.disconnected && this.ownPool) {
55
+ log('recreating pool after disconnect');
56
+ this.createPool();
57
+ }
58
+ // Test connection
59
+ const client = await this.pool.connect();
60
+ try {
61
+ await client.query('SELECT 1');
62
+ log('connection successful');
63
+ if (this.ensureSchema) {
64
+ await this.createSchema(client);
65
+ }
66
+ }
67
+ finally {
68
+ client.release();
69
+ }
70
+ }
71
+ async createSchema(client) {
72
+ log('ensuring schema exists');
73
+ // Create table
74
+ await client.query(getCreateTableSQL(this.tableName));
75
+ log('table created or already exists');
76
+ // Create indexes
77
+ for (const sql of getCreateIndexesSQL(this.tableName)) {
78
+ await client.query(sql);
79
+ }
80
+ log('indexes created or already exist');
81
+ // Create update trigger
82
+ await client.query(getUpdateTimestampTriggerSQL(this.tableName));
83
+ log('update trigger created');
84
+ }
85
+ async disconnect() {
86
+ log('disconnecting from PostgreSQL');
87
+ if (this.ownPool && this.pool && !this.disconnected) {
88
+ log('closing owned pool');
89
+ await this.pool.end();
90
+ this.disconnected = true;
91
+ }
92
+ }
93
+ /**
94
+ * Force close the pool - should only be called on application shutdown
95
+ * or when you're sure the backend won't be reused
96
+ */
97
+ async close() {
98
+ log('closing PostgreSQL pool');
99
+ if (this.ownPool && !this.disconnected) {
100
+ await this.pool.end();
101
+ this.disconnected = true;
102
+ }
103
+ }
104
+ /**
105
+ * Convert PostgreSQL row to JobParameters
106
+ */
107
+ rowToJob(row) {
108
+ return {
109
+ _id: toJobId(row.id),
110
+ name: row.name,
111
+ priority: row.priority,
112
+ nextRunAt: row.next_run_at,
113
+ type: row.type,
114
+ lockedAt: row.locked_at ?? undefined,
115
+ lastFinishedAt: row.last_finished_at ?? undefined,
116
+ failedAt: row.failed_at ?? undefined,
117
+ failCount: row.fail_count ?? undefined,
118
+ failReason: row.fail_reason ?? undefined,
119
+ repeatTimezone: row.repeat_timezone ?? undefined,
120
+ lastRunAt: row.last_run_at ?? undefined,
121
+ repeatInterval: row.repeat_interval ?? undefined,
122
+ data: row.data,
123
+ repeatAt: row.repeat_at ?? undefined,
124
+ disabled: row.disabled,
125
+ progress: row.progress ?? undefined,
126
+ fork: row.fork ?? undefined,
127
+ lastModifiedBy: row.last_modified_by ?? undefined
128
+ };
129
+ }
130
+ /**
131
+ * Convert SortDirection to SQL ASC/DESC
132
+ */
133
+ toSqlDirection(dir) {
134
+ return dir === 'asc' ? 'ASC' : 'DESC';
135
+ }
136
+ /**
137
+ * Convert sort options to PostgreSQL ORDER BY clause
138
+ */
139
+ toOrderByClause(sort) {
140
+ if (!sort) {
141
+ return 'next_run_at DESC NULLS LAST, last_run_at DESC NULLS LAST';
142
+ }
143
+ const parts = [];
144
+ if (sort.nextRunAt !== undefined) {
145
+ parts.push(`next_run_at ${this.toSqlDirection(sort.nextRunAt)} NULLS LAST`);
146
+ }
147
+ if (sort.lastRunAt !== undefined) {
148
+ parts.push(`last_run_at ${this.toSqlDirection(sort.lastRunAt)} NULLS LAST`);
149
+ }
150
+ if (sort.lastFinishedAt !== undefined) {
151
+ parts.push(`last_finished_at ${this.toSqlDirection(sort.lastFinishedAt)} NULLS LAST`);
152
+ }
153
+ if (sort.priority !== undefined) {
154
+ parts.push(`priority ${this.toSqlDirection(sort.priority)}`);
155
+ }
156
+ if (sort.name !== undefined) {
157
+ parts.push(`name ${this.toSqlDirection(sort.name)}`);
158
+ }
159
+ return parts.length > 0
160
+ ? parts.join(', ')
161
+ : 'next_run_at DESC NULLS LAST, last_run_at DESC NULLS LAST';
162
+ }
163
+ async getJobById(id) {
164
+ const result = await this.pool.query(`SELECT * FROM "${this.tableName}" WHERE id = $1`, [id]);
165
+ if (result.rows.length === 0) {
166
+ return null;
167
+ }
168
+ return this.rowToJob(result.rows[0]);
169
+ }
170
+ async queryJobs(options = {}) {
171
+ const { name, names, state, id, ids, search, data, includeDisabled = true, sort, skip = 0, limit = 0 } = options;
172
+ const now = new Date();
173
+ // Build query
174
+ const conditions = [];
175
+ const params = [];
176
+ let paramIndex = 1;
177
+ if (name) {
178
+ conditions.push(`name = $${paramIndex++}`);
179
+ params.push(name);
180
+ }
181
+ else if (names && names.length > 0) {
182
+ conditions.push(`name = ANY($${paramIndex++})`);
183
+ params.push(names);
184
+ }
185
+ if (id) {
186
+ conditions.push(`id = $${paramIndex++}`);
187
+ params.push(id);
188
+ }
189
+ else if (ids && ids.length > 0) {
190
+ conditions.push(`id = ANY($${paramIndex++}::uuid[])`);
191
+ params.push(ids);
192
+ }
193
+ if (search) {
194
+ conditions.push(`name ILIKE $${paramIndex++}`);
195
+ params.push(`%${search}%`);
196
+ }
197
+ if (data !== undefined) {
198
+ conditions.push(`data @> $${paramIndex++}::jsonb`);
199
+ params.push(JSON.stringify(data));
200
+ }
201
+ if (!includeDisabled) {
202
+ conditions.push('disabled = FALSE');
203
+ }
204
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
205
+ const orderByClause = this.toOrderByClause(sort);
206
+ const query = `
207
+ SELECT * FROM "${this.tableName}"
208
+ ${whereClause}
209
+ ORDER BY ${orderByClause}
210
+ `;
211
+ const result = await this.pool.query(query, params);
212
+ // Compute states and filter by state if specified
213
+ let jobsWithState = result.rows
214
+ .map(row => {
215
+ const job = this.rowToJob(row);
216
+ return {
217
+ ...job,
218
+ _id: job._id,
219
+ state: computeJobState(job, now)
220
+ };
221
+ })
222
+ .filter(job => !state || job.state === state);
223
+ // Apply pagination after state filtering
224
+ const total = jobsWithState.length;
225
+ if (limit > 0) {
226
+ jobsWithState = jobsWithState.slice(skip, skip + limit);
227
+ }
228
+ else if (skip > 0) {
229
+ jobsWithState = jobsWithState.slice(skip);
230
+ }
231
+ return { jobs: jobsWithState, total };
232
+ }
233
+ async getJobsOverview() {
234
+ const now = new Date();
235
+ const names = await this.getDistinctJobNames();
236
+ const overviews = await Promise.all(names.map(async (name) => {
237
+ const result = await this.pool.query(`SELECT * FROM "${this.tableName}" WHERE name = $1`, [name]);
238
+ const overview = {
239
+ name,
240
+ total: result.rows.length,
241
+ running: 0,
242
+ scheduled: 0,
243
+ queued: 0,
244
+ completed: 0,
245
+ failed: 0,
246
+ repeating: 0
247
+ };
248
+ for (const row of result.rows) {
249
+ const job = this.rowToJob(row);
250
+ const state = computeJobState(job, now);
251
+ overview[state]++;
252
+ }
253
+ return overview;
254
+ }));
255
+ return overviews;
256
+ }
257
+ async getDistinctJobNames() {
258
+ const result = await this.pool.query(`SELECT DISTINCT name FROM "${this.tableName}" ORDER BY name`);
259
+ return result.rows.map(row => row.name);
260
+ }
261
+ async getQueueSize() {
262
+ const result = await this.pool.query(`SELECT COUNT(*) as count FROM "${this.tableName}" WHERE next_run_at < NOW()`);
263
+ return parseInt(result.rows[0].count, 10);
264
+ }
265
+ async removeJobs(options) {
266
+ const conditions = [];
267
+ const params = [];
268
+ let paramIndex = 1;
269
+ if (options.id) {
270
+ conditions.push(`id = $${paramIndex++}`);
271
+ params.push(options.id.toString());
272
+ }
273
+ else if (options.ids && options.ids.length > 0) {
274
+ conditions.push(`id = ANY($${paramIndex++}::uuid[])`);
275
+ params.push(options.ids.map(id => id.toString()));
276
+ }
277
+ if (options.name) {
278
+ conditions.push(`name = $${paramIndex++}`);
279
+ params.push(options.name);
280
+ }
281
+ else if (options.names && options.names.length > 0) {
282
+ conditions.push(`name = ANY($${paramIndex++})`);
283
+ params.push(options.names);
284
+ }
285
+ else if (options.notNames && options.notNames.length > 0) {
286
+ conditions.push(`name != ALL($${paramIndex++})`);
287
+ params.push(options.notNames);
288
+ }
289
+ if (options.data !== undefined) {
290
+ conditions.push(`data @> $${paramIndex++}::jsonb`);
291
+ params.push(JSON.stringify(options.data));
292
+ }
293
+ // If no criteria provided, don't delete anything
294
+ if (conditions.length === 0) {
295
+ return 0;
296
+ }
297
+ const result = await this.pool.query(`DELETE FROM "${this.tableName}" WHERE ${conditions.join(' AND ')}`, params);
298
+ return result.rowCount || 0;
299
+ }
300
+ async unlockJob(job) {
301
+ if (!job._id)
302
+ return;
303
+ // Only unlock jobs which are not currently processed (nextRunAt is not null)
304
+ await this.pool.query(`UPDATE "${this.tableName}"
305
+ SET locked_at = NULL
306
+ WHERE id = $1 AND next_run_at IS NOT NULL`, [job._id.toString()]);
307
+ }
308
+ async unlockJobs(jobIds) {
309
+ if (jobIds.length === 0)
310
+ return;
311
+ const ids = jobIds.map(id => id.toString());
312
+ await this.pool.query(`UPDATE "${this.tableName}"
313
+ SET locked_at = NULL
314
+ WHERE id = ANY($1::uuid[])`, [ids]);
315
+ }
316
+ async lockJob(job, options) {
317
+ if (!job._id)
318
+ return undefined;
319
+ const orderBy = `next_run_at ${this.toSqlDirection(this.sort.nextRunAt || 'asc')} NULLS LAST, priority ${this.toSqlDirection(this.sort.priority || 'desc')}`;
320
+ // Atomic lock using UPDATE ... RETURNING
321
+ const result = await this.pool.query(`UPDATE "${this.tableName}"
322
+ SET locked_at = NOW(), last_modified_by = $4
323
+ WHERE id = (
324
+ SELECT id FROM "${this.tableName}"
325
+ WHERE id = $1
326
+ AND name = $2
327
+ AND locked_at IS NULL
328
+ AND next_run_at = $3
329
+ AND disabled = FALSE
330
+ ORDER BY ${orderBy}
331
+ LIMIT 1
332
+ FOR UPDATE SKIP LOCKED
333
+ )
334
+ RETURNING *`, [job._id.toString(), job.name, job.nextRunAt, options?.lastModifiedBy || null]);
335
+ if (result.rows.length === 0) {
336
+ return undefined;
337
+ }
338
+ return this.rowToJob(result.rows[0]);
339
+ }
340
+ async getNextJobToRun(jobName, nextScanAt, lockDeadline, now, options) {
341
+ const lockTime = now ?? new Date();
342
+ const orderBy = `next_run_at ${this.toSqlDirection(this.sort.nextRunAt || 'asc')} NULLS LAST, priority ${this.toSqlDirection(this.sort.priority || 'desc')}`;
343
+ // Find and lock job atomically using UPDATE ... RETURNING with subquery
344
+ const result = await this.pool.query(`UPDATE "${this.tableName}"
345
+ SET locked_at = $1, last_modified_by = $5
346
+ WHERE id = (
347
+ SELECT id FROM "${this.tableName}"
348
+ WHERE name = $2
349
+ AND disabled = FALSE
350
+ AND (
351
+ (locked_at IS NULL AND next_run_at <= $3)
352
+ OR locked_at <= $4
353
+ )
354
+ ORDER BY ${orderBy}
355
+ LIMIT 1
356
+ FOR UPDATE SKIP LOCKED
357
+ )
358
+ RETURNING *`, [lockTime, jobName, nextScanAt, lockDeadline, options?.lastModifiedBy || null]);
359
+ if (result.rows.length === 0) {
360
+ return undefined;
361
+ }
362
+ return this.rowToJob(result.rows[0]);
363
+ }
364
+ async saveJobState(job, options) {
365
+ if (!job._id) {
366
+ throw new Error('Cannot save job state without job ID');
367
+ }
368
+ const result = await this.pool.query(`UPDATE "${this.tableName}"
369
+ SET locked_at = $2,
370
+ next_run_at = $3,
371
+ last_run_at = $4,
372
+ progress = $5,
373
+ fail_reason = $6,
374
+ fail_count = $7,
375
+ failed_at = $8,
376
+ last_finished_at = $9,
377
+ last_modified_by = $11
378
+ WHERE id = $1 AND name = $10`, [
379
+ job._id.toString(),
380
+ job.lockedAt || null,
381
+ job.nextRunAt || null,
382
+ job.lastRunAt || null,
383
+ job.progress ?? null,
384
+ job.failReason ?? null,
385
+ job.failCount ?? null,
386
+ job.failedAt || null,
387
+ job.lastFinishedAt || null,
388
+ job.name,
389
+ options?.lastModifiedBy || null
390
+ ]);
391
+ if (result.rowCount !== 1) {
392
+ throw new Error(`job ${job._id} (name: ${job.name}) cannot be updated in the database, maybe it does not exist anymore?`);
393
+ }
394
+ }
395
+ async saveJob(job, options) {
396
+ log('attempting to save a job');
397
+ const { _id, unique, uniqueOpts, ...props } = job;
398
+ // If the job already has an ID, update it
399
+ if (_id) {
400
+ log('job already has _id, updating');
401
+ const result = await this.pool.query(`UPDATE "${this.tableName}"
402
+ SET name = $2,
403
+ priority = $3,
404
+ next_run_at = $4,
405
+ type = $5,
406
+ repeat_timezone = $6,
407
+ repeat_interval = $7,
408
+ data = $8,
409
+ repeat_at = $9,
410
+ disabled = $10,
411
+ fork = $11,
412
+ fail_reason = $12,
413
+ fail_count = $13,
414
+ failed_at = $14,
415
+ last_modified_by = $15
416
+ WHERE id = $1 AND name = $2
417
+ RETURNING *`, [
418
+ _id.toString(),
419
+ props.name,
420
+ props.priority,
421
+ props.nextRunAt || null,
422
+ props.type,
423
+ props.repeatTimezone || null,
424
+ props.repeatInterval || null,
425
+ JSON.stringify(props.data),
426
+ props.repeatAt || null,
427
+ props.disabled || false,
428
+ props.fork || false,
429
+ props.failReason ?? null,
430
+ props.failCount ?? null,
431
+ props.failedAt || null,
432
+ options?.lastModifiedBy || null
433
+ ]);
434
+ if (result.rows.length === 0) {
435
+ // Job was removed, return original data unchanged
436
+ log('job %s was not found for update, returning original data', _id);
437
+ return job;
438
+ }
439
+ return this.rowToJob(result.rows[0]);
440
+ }
441
+ // Handle 'single' type jobs - upsert by name
442
+ if (props.type === 'single') {
443
+ log('job with type of "single" found');
444
+ const now = new Date();
445
+ const shouldProtectNextRunAt = props.nextRunAt && props.nextRunAt <= now;
446
+ // Use ON CONFLICT to upsert
447
+ const result = await this.pool.query(`INSERT INTO "${this.tableName}" (
448
+ name, priority, next_run_at, type, repeat_timezone,
449
+ repeat_interval, data, repeat_at, disabled, fork, last_modified_by
450
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
451
+ ON CONFLICT ((name)) WHERE type = 'single'
452
+ DO UPDATE SET
453
+ priority = EXCLUDED.priority,
454
+ next_run_at = ${shouldProtectNextRunAt
455
+ ? `COALESCE("${this.tableName}".next_run_at, EXCLUDED.next_run_at)`
456
+ : 'EXCLUDED.next_run_at'},
457
+ repeat_timezone = EXCLUDED.repeat_timezone,
458
+ repeat_interval = EXCLUDED.repeat_interval,
459
+ data = EXCLUDED.data,
460
+ repeat_at = EXCLUDED.repeat_at,
461
+ disabled = EXCLUDED.disabled,
462
+ fork = EXCLUDED.fork,
463
+ last_modified_by = EXCLUDED.last_modified_by
464
+ RETURNING *`, [
465
+ props.name,
466
+ props.priority,
467
+ props.nextRunAt || null,
468
+ props.type,
469
+ props.repeatTimezone || null,
470
+ props.repeatInterval || null,
471
+ JSON.stringify(props.data),
472
+ props.repeatAt || null,
473
+ props.disabled || false,
474
+ props.fork || false,
475
+ options?.lastModifiedBy || null
476
+ ]);
477
+ return this.rowToJob(result.rows[0]);
478
+ }
479
+ // Handle unique constraint
480
+ if (unique) {
481
+ log('calling upsert with unique constraint');
482
+ // Build conditions from unique object
483
+ const conditions = ['name = $1'];
484
+ const params = [props.name];
485
+ let paramIndex = 2;
486
+ for (const [key, value] of Object.entries(unique)) {
487
+ if (key.startsWith('data.')) {
488
+ // Handle data sub-paths like 'data.userId'
489
+ const dataPath = key.substring(5);
490
+ conditions.push(`data->>'${dataPath}' = $${paramIndex++}`);
491
+ params.push(String(value));
492
+ }
493
+ else {
494
+ // Direct column (snake_case conversion)
495
+ const columnName = key.replace(/([A-Z])/g, '_$1').toLowerCase();
496
+ conditions.push(`${columnName} = $${paramIndex++}`);
497
+ params.push(value);
498
+ }
499
+ }
500
+ // Check if record exists
501
+ const existingResult = await this.pool.query(`SELECT * FROM "${this.tableName}" WHERE ${conditions.join(' AND ')} LIMIT 1`, params);
502
+ if (existingResult.rows.length > 0) {
503
+ // Record exists
504
+ if (uniqueOpts?.insertOnly) {
505
+ // Return existing record without update
506
+ return this.rowToJob(existingResult.rows[0]);
507
+ }
508
+ // Update existing record
509
+ const updateResult = await this.pool.query(`UPDATE "${this.tableName}"
510
+ SET priority = $${paramIndex},
511
+ next_run_at = $${paramIndex + 1},
512
+ type = $${paramIndex + 2},
513
+ repeat_timezone = $${paramIndex + 3},
514
+ repeat_interval = $${paramIndex + 4},
515
+ data = $${paramIndex + 5},
516
+ repeat_at = $${paramIndex + 6},
517
+ disabled = $${paramIndex + 7},
518
+ fork = $${paramIndex + 8},
519
+ last_modified_by = $${paramIndex + 9}
520
+ WHERE ${conditions.join(' AND ')}
521
+ RETURNING *`, [
522
+ ...params,
523
+ props.priority,
524
+ props.nextRunAt || null,
525
+ props.type,
526
+ props.repeatTimezone || null,
527
+ props.repeatInterval || null,
528
+ JSON.stringify(props.data),
529
+ props.repeatAt || null,
530
+ props.disabled || false,
531
+ props.fork || false,
532
+ options?.lastModifiedBy || null
533
+ ]);
534
+ return this.rowToJob(updateResult.rows[0]);
535
+ }
536
+ }
537
+ // Insert new job
538
+ log('inserting new job');
539
+ const result = await this.pool.query(`INSERT INTO "${this.tableName}" (
540
+ name, priority, next_run_at, type, repeat_timezone,
541
+ repeat_interval, data, repeat_at, disabled, fork, last_modified_by
542
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
543
+ RETURNING *`, [
544
+ props.name,
545
+ props.priority,
546
+ props.nextRunAt || null,
547
+ props.type,
548
+ props.repeatTimezone || null,
549
+ props.repeatInterval || null,
550
+ JSON.stringify(props.data),
551
+ props.repeatAt || null,
552
+ props.disabled || false,
553
+ props.fork || false,
554
+ options?.lastModifiedBy || null
555
+ ]);
556
+ return this.rowToJob(result.rows[0]);
557
+ }
558
+ }
559
+ //# sourceMappingURL=PostgresJobRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresJobRepository.js","sourceRoot":"","sources":["../src/PostgresJobRepository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { Pool } from 'pg';
2
+ import type { JobNotification, NotificationChannelConfig } from 'agenda';
3
+ import { BaseNotificationChannel } from 'agenda';
4
+ /**
5
+ * Configuration for PostgresNotificationChannel
6
+ */
7
+ export interface PostgresNotificationChannelConfig extends NotificationChannelConfig {
8
+ /** PostgreSQL connection pool (shared with repository) */
9
+ pool?: Pool;
10
+ /** PostgreSQL connection string (if not sharing pool) */
11
+ connectionString?: string;
12
+ }
13
+ /**
14
+ * PostgreSQL notification channel using LISTEN/NOTIFY
15
+ *
16
+ * This implementation uses PostgreSQL's built-in pub/sub mechanism
17
+ * for real-time job notifications across multiple processes.
18
+ */
19
+ export declare class PostgresNotificationChannel extends BaseNotificationChannel {
20
+ private pool?;
21
+ private ownPool;
22
+ private connectionString?;
23
+ private listenClient?;
24
+ constructor(config?: PostgresNotificationChannelConfig);
25
+ /**
26
+ * Set the pool (used when created by PostgresBackend)
27
+ */
28
+ setPool(pool: Pool): void;
29
+ connect(): Promise<void>;
30
+ private handleConnectionLoss;
31
+ disconnect(): Promise<void>;
32
+ publish(notification: JobNotification): Promise<void>;
33
+ /**
34
+ * Serialize notification to JSON string for NOTIFY payload
35
+ */
36
+ private serializeNotification;
37
+ /**
38
+ * Parse notification from JSON string received via LISTEN
39
+ */
40
+ private parseNotification;
41
+ }