mail-time 3.0.0 → 4.1.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,118 @@
1
+ export type MongoCollection = {
2
+ collectionName?: string | undefined;
3
+ createIndex: (keys: object, opts?: object) => Promise<unknown>;
4
+ indexes: () => Promise<{
5
+ name: string;
6
+ key: Record<string, unknown>;
7
+ }[]>;
8
+ dropIndex: (name: string) => Promise<unknown>;
9
+ find: (query: object, opts?: object) => unknown;
10
+ findOne: (query: object, opts?: object) => Promise<object | null>;
11
+ insertOne: (doc: object) => Promise<unknown>;
12
+ deleteOne: (query: object) => Promise<{
13
+ deletedCount?: number;
14
+ }>;
15
+ updateOne: (query: object, update: object) => Promise<{
16
+ modifiedCount?: number;
17
+ }>;
18
+ };
19
+ export type Db = {
20
+ collection: (name: string) => MongoCollection;
21
+ command: (cmd: object) => Promise<{
22
+ ok?: number;
23
+ }>;
24
+ };
25
+ export type MongoQueueOption = {
26
+ db: Db;
27
+ prefix?: string | undefined;
28
+ };
29
+ /** Class representing MongoDB Queue for MailTime */
30
+ export class MongoQueue {
31
+ /**
32
+ * Create a MongoQueue instance
33
+ * @param {MongoQueueOption} opts - configuration object
34
+ */
35
+ constructor(opts: MongoQueueOption);
36
+ name: string;
37
+ db: Db;
38
+ prefix: any;
39
+ collection: MongoCollection | undefined;
40
+ /**
41
+ * @async
42
+ * @memberOf MongoQueue
43
+ * @name ready
44
+ * @description Wait until indexes are created
45
+ * @returns {Promise<void 0>}
46
+ */
47
+ ready(): Promise<void>;
48
+ /**
49
+ * @async
50
+ * @memberOf MongoQueue
51
+ * @name ping
52
+ * @description Check connection to Storage
53
+ * @returns {Promise<object>}
54
+ */
55
+ ping(): Promise<object>;
56
+ /**
57
+ * @memberOf MongoQueue
58
+ * @name iterate
59
+ * @description iterate over queued tasks passing each to `mailTimeInstance.___dispatch` (the bounded send pool)
60
+ * @param {{ limit?: number, sendingTimeout?: number }} [opts] - iteration options
61
+ * @returns {Promise<void>}
62
+ */
63
+ iterate(opts?: {
64
+ limit?: number;
65
+ sendingTimeout?: number;
66
+ }): Promise<void>;
67
+ /**
68
+ * @async
69
+ * @memberOf MongoQueue
70
+ * @name getPendingTo
71
+ * @description get queued task by `to` field (addressee)
72
+ * @param to {string} - email address
73
+ * @param sendAt {number} - timestamp
74
+ * @returns {Promise<object|null>}
75
+ */
76
+ getPendingTo(to: string, sendAt: number): Promise<object | null>;
77
+ /**
78
+ * @async
79
+ * @memberOf MongoQueue
80
+ * @name push
81
+ * @description push task to the queue/storage
82
+ * @param task {object} - task's object
83
+ * @returns {Promise<void 0>}
84
+ */
85
+ push(task: object): Promise<void>;
86
+ /**
87
+ * @async
88
+ * @memberOf MongoQueue
89
+ * @name cancel
90
+ * @description cancel scheduled email
91
+ * @param uuid {string} - email's uuid
92
+ * @returns {Promise<boolean>} returns `true` if cancelled or `false` if not found, was sent, or was cancelled previously
93
+ */
94
+ cancel(uuid: string): Promise<boolean>;
95
+ /**
96
+ * @async
97
+ * @memberOf MongoQueue
98
+ * @name remove
99
+ * @description remove task from queue
100
+ * @param task {object} - task's object
101
+ * @param {{ leaseTries: number, leaseSendingAt: number }} [opts] - lease guard: only remove if this worker still holds the lease (tries + sendingAt match, row not cancelled/failed)
102
+ * @returns {Promise<boolean>} returns `true` if removed or `false` if not found
103
+ */
104
+ remove(task: object, opts?: {
105
+ leaseTries: number;
106
+ leaseSendingAt: number;
107
+ }): Promise<boolean>;
108
+ /**
109
+ * @async
110
+ * @memberOf MongoQueue
111
+ * @name update
112
+ * @description update task in queue
113
+ * @param task {object} - task's object
114
+ * @param updateObj {object} - fields with new values to update
115
+ * @returns {Promise<boolean>} returns `true` if updated or `false` if not found or no changes was made
116
+ */
117
+ update(task: object, updateObj: object): Promise<boolean>;
118
+ }
package/adapters/mongo.js CHANGED
@@ -1,37 +1,62 @@
1
- import { logError } from '../helpers.js';
1
+ import {
2
+ debug,
3
+ logError,
4
+ isSendClaimUpdate,
5
+ isSendLeaseGuardedUpdate,
6
+ isAppendMailOptionUpdate,
7
+ stripInternalUpdateMeta,
8
+ isSendLeaseRemove,
9
+ } from '../helpers.js';
10
+
11
+ const DEFAULT_PREFIX = '';
12
+
13
+ /**
14
+ * @typedef {object} MongoCollection
15
+ * @property {string} [collectionName]
16
+ * @property {(keys: object, opts?: object) => Promise<unknown>} createIndex
17
+ * @property {() => Promise<{ name: string, key: Record<string, unknown> }[]>} indexes
18
+ * @property {(name: string) => Promise<unknown>} dropIndex
19
+ * @property {(query: object, opts?: object) => unknown} find
20
+ * @property {(query: object, opts?: object) => Promise<object|null>} findOne
21
+ * @property {(doc: object) => Promise<unknown>} insertOne
22
+ * @property {(query: object) => Promise<{ deletedCount?: number }>} deleteOne
23
+ * @property {(query: object, update: object) => Promise<{ modifiedCount?: number }>} updateOne
24
+ */
25
+
26
+ /**
27
+ * @typedef {object} Db
28
+ * @property {(name: string) => MongoCollection} collection
29
+ * @property {(cmd: object) => Promise<{ ok?: number }>} command
30
+ */
2
31
 
3
32
  /**
4
- * Ensure (create) index on MongoDB collection, catch and log exception if thrown
5
- * @function ensureIndex
6
- * @param {Collection} collection - Mongo's driver Collection instance
7
- * @param {object} keys - Field and value pairs where the field is the index key and the value describes the type of index for that field
8
- * @param {object} opts - Set of options that controls the creation of the index
9
- * @returns {void 0}
33
+ * @typedef {object} MongoQueueOption
34
+ * @property {Db} db
35
+ * @property {string} [prefix]
10
36
  */
37
+
38
+ /** @internal */
11
39
  const ensureIndex = async (collection, keys, opts) => {
12
40
  try {
13
41
  await collection.createIndex(keys, opts);
14
42
  } catch (e) {
15
- if (e.code === 85) {
43
+ if (e?.code === 85) {
16
44
  let indexName;
17
45
  const indexes = await collection.indexes();
46
+ const keyNames = Object.keys(keys);
18
47
  for (const index of indexes) {
19
- let drop = true;
20
- for (const indexKey of Object.keys(keys)) {
21
- if (typeof index.key[indexKey] === 'undefined') {
22
- drop = false;
23
- break;
24
- }
48
+ const indexKeys = Object.keys(index.key);
49
+ if (indexKeys.length !== keyNames.length) {
50
+ continue;
25
51
  }
26
-
27
- for (const indexKey of Object.keys(index.key)) {
28
- if (typeof keys[indexKey] === 'undefined') {
29
- drop = false;
52
+ let match = true;
53
+ for (const k of keyNames) {
54
+ if (typeof index.key[k] === 'undefined') {
55
+ match = false;
30
56
  break;
31
57
  }
32
58
  }
33
-
34
- if (drop) {
59
+ if (match) {
35
60
  indexName = index.name;
36
61
  break;
37
62
  }
@@ -42,7 +67,7 @@ const ensureIndex = async (collection, keys, opts) => {
42
67
  await collection.createIndex(keys, opts);
43
68
  }
44
69
  } else {
45
- logError(`[ensureIndex] Can not set ${Object.keys(keys).join(' + ')} index on "${collection._name || 'MongoDB'}" collection`, { keys, opts, details: e });
70
+ logError(`[ensureIndex] Can not set ${Object.keys(keys).join(' + ')} index on "${collection?.collectionName || 'MongoDB'}" collection`, { keys, opts, details: e });
46
71
  }
47
72
  }
48
73
  };
@@ -51,47 +76,58 @@ const ensureIndex = async (collection, keys, opts) => {
51
76
  class MongoQueue {
52
77
  /**
53
78
  * Create a MongoQueue instance
54
- * @param {object} opts - configuration object
55
- * @param {Db} opts.db - Required, Mongo's `Db` instance, like one returned from `MongoClient#db()` method
56
- * @param {string} [opts.prefix] - Optional prefix for scope isolation; use when creating multiple MailTime instances within the single application
79
+ * @param {MongoQueueOption} opts - configuration object
57
80
  */
58
81
  constructor (opts) {
59
82
  this.name = 'mongo-queue';
60
- if (!opts || typeof opts !== 'object' || opts === null) {
83
+ if (!opts || typeof opts !== 'object') {
61
84
  throw new TypeError('[mail-time] Configuration object must be passed into MongoQueue constructor');
62
85
  }
63
86
 
64
87
  if (!opts.db) {
65
- throw new Error('[mail-time] [MongoQueue] requires MongoDB database {db} option, like returned from `MongoClient.connect`');
88
+ throw new Error('[mail-time] [MongoQueue] requires MongoDB database {db} option, like returned from `MongoClient#db()`');
66
89
  }
67
90
 
68
- this.prefix = (typeof opts.prefix === 'string') ? opts.prefix : '';
69
91
  this.db = opts.db;
70
- this.collection = opts.db.collection(`__mailTimeQueue__${this.prefix}`);
71
- ensureIndex(this.collection, { uuid: 1 }, { background: false });
72
- ensureIndex(this.collection, { isSent: 1, isFailed: 1, isCancelled: 1, to: 1, sendAt: 1 }, { background: false });
73
- ensureIndex(this.collection, { isSent: 1, isFailed: 1, isCancelled: 1, sendAt: 1, tries: 1 }, { background: false });
74
-
75
- // MongoDB Collection Schema:
76
- // _id
77
- // uuid {string}
78
- // to {string|[string]}
79
- // tries {number} - qty of send attempts
80
- // sendAt {number} - When letter should be sent
81
- // isSent {boolean} - Email status
82
- // isCancelled {boolean} - `true` if email was cancelled before it was sent
83
- // isFailed {boolean} - `true` if email has failed to send
84
- // template {string} - Template for this email
85
- // transport {number} - Last used transport
86
- // concatSubject {string|boolean} - Email concatenation subject
87
- // ---
88
- // mailOptions {[object]} - Array of nodeMailer's `mailOptions`
89
- // mailOptions.to {string|[string]} - [REQUIRED]
90
- // mailOptions.from {string}
91
- // mailOptions.text {string|boolean}
92
- // mailOptions.html {string}
93
- // mailOptions.subject {string}
94
- // mailOptions.Other nodeMailer `sendMail` options...
92
+ if (typeof opts.prefix === 'string') {
93
+ this.__applyPrefix(opts.prefix);
94
+ }
95
+ }
96
+
97
+ /** @internal */
98
+ __applyPrefix(prefix) {
99
+ this.prefix = prefix;
100
+ this.collection = this.db.collection(`__mailTimeQueue__${prefix}`);
101
+ this.__readyPromise = Promise.all([
102
+ ensureIndex(this.collection, { uuid: 1 }, { background: false }),
103
+ ensureIndex(this.collection, { isSent: 1, isFailed: 1, isCancelled: 1, to: 1, sendAt: 1 }, { background: false }),
104
+ ensureIndex(this.collection, { isSent: 1, isFailed: 1, isCancelled: 1, isSending: 1, sendingAt: 1, sendAt: 1, tries: 1 }, { background: false }),
105
+ ]).then(() => void 0);
106
+ }
107
+
108
+ /** @internal */
109
+ __ensurePrefix() {
110
+ if (typeof this.prefix !== 'string') {
111
+ this.__applyPrefix(this.mailTimeInstance?.prefix || DEFAULT_PREFIX);
112
+ }
113
+ }
114
+
115
+ /** @internal */
116
+ __debug(...args) {
117
+ debug(this.mailTimeInstance?.debug === true, `[${this.name}]`, ...args);
118
+ }
119
+
120
+ /**
121
+ * @async
122
+ * @memberOf MongoQueue
123
+ * @name ready
124
+ * @description Wait until indexes are created
125
+ * @returns {Promise<void 0>}
126
+ */
127
+ async ready() {
128
+ this.__ensurePrefix();
129
+ this.__debug('[ready]');
130
+ await this.__readyPromise;
95
131
  }
96
132
 
97
133
  /**
@@ -102,6 +138,7 @@ class MongoQueue {
102
138
  * @returns {Promise<object>}
103
139
  */
104
140
  async ping() {
141
+ this.__debug('[ping]');
105
142
  if (!this.mailTimeInstance) {
106
143
  return {
107
144
  status: 'Service Unavailable',
@@ -125,7 +162,7 @@ class MongoQueue {
125
162
  status: 'Internal Server Error',
126
163
  code: 500,
127
164
  statusCode: 500,
128
- error: pingError
165
+ error: pingError,
129
166
  };
130
167
  }
131
168
 
@@ -133,28 +170,43 @@ class MongoQueue {
133
170
  status: 'Service Unavailable',
134
171
  code: 503,
135
172
  statusCode: 503,
136
- error: new Error('Service Unavailable')
173
+ error: new Error('Service Unavailable'),
137
174
  };
138
175
  }
139
176
 
140
177
  /**
141
178
  * @memberOf MongoQueue
142
179
  * @name iterate
143
- * @description iterate over queued tasks passing to `mailTimeInstance.___send` method
144
- * @returns {void 0}
180
+ * @description iterate over queued tasks passing each to `mailTimeInstance.___dispatch` (the bounded send pool)
181
+ * @param {{ limit?: number, sendingTimeout?: number }} [opts] - iteration options
182
+ * @returns {Promise<void>}
145
183
  */
146
- async iterate() {
184
+ async iterate(opts) {
185
+ this.__debug('[iterate]', opts);
186
+ this.__ensurePrefix();
187
+ const now = Date.now();
188
+ const sendingTimeout = (opts && typeof opts.sendingTimeout === 'number' && opts.sendingTimeout > 0)
189
+ ? opts.sendingTimeout
190
+ : 300000;
191
+ const limit = (opts && typeof opts.limit === 'number' && Number.isFinite(opts.limit) && opts.limit > 0)
192
+ ? Math.floor(opts.limit)
193
+ : 0;
194
+
147
195
  try {
148
196
  const cursor = this.collection.find({
149
197
  isSent: false,
150
198
  isFailed: false,
151
199
  isCancelled: false,
152
200
  sendAt: {
153
- $lte: Date.now()
201
+ $lte: now,
154
202
  },
155
203
  tries: {
156
- $lt: this.mailTimeInstance.maxTries
157
- }
204
+ $lt: this.mailTimeInstance.maxTries,
205
+ },
206
+ $or: [
207
+ { isSending: { $ne: true } },
208
+ { sendingAt: { $lte: now - sendingTimeout } },
209
+ ],
158
210
  }, {
159
211
  projection: {
160
212
  _id: 1,
@@ -165,15 +217,24 @@ class MongoQueue {
165
217
  isSent: 1,
166
218
  isFailed: 1,
167
219
  isCancelled: 1,
220
+ isSending: 1,
221
+ sendingAt: 1,
168
222
  mailOptions: 1,
169
223
  concatSubject: 1,
170
- }
224
+ },
171
225
  });
172
226
 
173
- while (await cursor.hasNext()) {
174
- await this.mailTimeInstance.___send(await cursor.next());
227
+ if (limit > 0) {
228
+ cursor.limit(limit);
229
+ }
230
+
231
+ try {
232
+ while (await cursor.hasNext()) {
233
+ await this.mailTimeInstance.___dispatch(await cursor.next());
234
+ }
235
+ } finally {
236
+ await cursor.close().catch(() => {});
175
237
  }
176
- await cursor.close();
177
238
  } catch (iterateError) {
178
239
  logError('[iterate] [while/await] [iterateError]', iterateError);
179
240
  }
@@ -189,18 +250,22 @@ class MongoQueue {
189
250
  * @returns {Promise<object|null>}
190
251
  */
191
252
  async getPendingTo(to, sendAt) {
253
+ this.__debug('[getPendingTo]', to, sendAt);
192
254
  if (typeof to !== 'string' || typeof sendAt !== 'number') {
193
255
  return null;
194
256
  }
257
+ this.__ensurePrefix();
195
258
 
196
259
  return await this.collection.findOne({
197
- to: to,
260
+ to,
198
261
  isSent: false,
199
262
  isFailed: false,
200
263
  isCancelled: false,
264
+ isSending: { $ne: true },
265
+ tries: { $lt: this.mailTimeInstance.maxTries },
201
266
  sendAt: {
202
- $lte: sendAt
203
- }
267
+ $lte: sendAt,
268
+ },
204
269
  }, {
205
270
  projection: {
206
271
  _id: 1,
@@ -211,7 +276,7 @@ class MongoQueue {
211
276
  isFailed: 1,
212
277
  isCancelled: 1,
213
278
  mailOptions: 1,
214
- }
279
+ },
215
280
  });
216
281
  }
217
282
 
@@ -224,9 +289,11 @@ class MongoQueue {
224
289
  * @returns {Promise<void 0>}
225
290
  */
226
291
  async push(task) {
227
- if (typeof task !== 'object') {
292
+ this.__debug('[push]', task?.uuid);
293
+ if (!task || typeof task !== 'object') {
228
294
  return;
229
295
  }
296
+ this.__ensurePrefix();
230
297
 
231
298
  if (task.sendAt instanceof Date) {
232
299
  task.sendAt = +task.sendAt;
@@ -243,9 +310,11 @@ class MongoQueue {
243
310
  * @returns {Promise<boolean>} returns `true` if cancelled or `false` if not found, was sent, or was cancelled previously
244
311
  */
245
312
  async cancel(uuid) {
313
+ this.__debug('[cancel]', uuid);
246
314
  if (typeof uuid !== 'string') {
247
315
  return false;
248
316
  }
317
+ this.__ensurePrefix();
249
318
 
250
319
  const task = await this.collection.findOne({ uuid }, {
251
320
  projection: {
@@ -253,7 +322,7 @@ class MongoQueue {
253
322
  uuid: 1,
254
323
  isSent: 1,
255
324
  isCancelled: 1,
256
- }
325
+ },
257
326
  });
258
327
 
259
328
  if (!task || task.isSent === true || task.isCancelled === true) {
@@ -275,35 +344,90 @@ class MongoQueue {
275
344
  * @name remove
276
345
  * @description remove task from queue
277
346
  * @param task {object} - task's object
347
+ * @param {{ leaseTries: number, leaseSendingAt: number }} [opts] - lease guard: only remove if this worker still holds the lease (tries + sendingAt match, row not cancelled/failed)
278
348
  * @returns {Promise<boolean>} returns `true` if removed or `false` if not found
279
349
  */
280
- async remove(task) {
281
- if (typeof task !== 'object') {
350
+ async remove(task, opts) {
351
+ this.__debug('[remove]', task?.uuid);
352
+ if (!task || typeof task !== 'object') {
282
353
  return false;
283
354
  }
355
+ this.__ensurePrefix();
284
356
 
285
- return (await this.collection.deleteOne({ _id: task._id }))?.deletedCount >= 1;
357
+ const query = { _id: task._id };
358
+ if (isSendLeaseRemove(opts)) {
359
+ query.tries = opts.leaseTries;
360
+ query.isSending = true;
361
+ query.sendingAt = opts.leaseSendingAt;
362
+ query.isCancelled = false;
363
+ query.isFailed = false;
364
+ }
365
+
366
+ const res = await this.collection.deleteOne(query);
367
+ return (res?.deletedCount || 0) >= 1;
286
368
  }
287
369
 
288
370
  /**
289
371
  * @async
290
372
  * @memberOf MongoQueue
291
373
  * @name update
292
- * @description remove task from queue
374
+ * @description update task in queue
293
375
  * @param task {object} - task's object
294
376
  * @param updateObj {object} - fields with new values to update
295
377
  * @returns {Promise<boolean>} returns `true` if updated or `false` if not found or no changes was made
296
378
  */
297
379
  async update(task, updateObj) {
298
- if (typeof task !== 'object' || typeof updateObj !== 'object') {
380
+ this.__debug('[update]', task?.uuid);
381
+ if (!task || typeof task !== 'object' || !updateObj || typeof updateObj !== 'object') {
299
382
  return false;
300
383
  }
384
+ this.__ensurePrefix();
301
385
 
302
- return (await this.collection.updateOne({
303
- _id: task._id
304
- }, {
305
- $set: updateObj
306
- }))?.modifiedCount >= 1;
386
+ if (isAppendMailOptionUpdate(updateObj)) {
387
+ const res = await this.collection.updateOne({
388
+ _id: task._id,
389
+ isSent: false,
390
+ isFailed: false,
391
+ isCancelled: false,
392
+ isSending: { $ne: true },
393
+ }, {
394
+ $push: {
395
+ mailOptions: updateObj.appendMailOption,
396
+ },
397
+ });
398
+ return (res?.modifiedCount || 0) >= 1;
399
+ }
400
+
401
+ const query = {
402
+ _id: task._id,
403
+ };
404
+
405
+ if (isSendClaimUpdate(updateObj)) {
406
+ const now = typeof updateObj.sendingAt === 'number' ? updateObj.sendingAt : Date.now();
407
+ const sendingTimeout = this.mailTimeInstance?.sendingTimeout || 300000;
408
+ query.isSent = false;
409
+ query.isFailed = false;
410
+ query.isCancelled = false;
411
+ query.tries = task.tries;
412
+ query.$or = [
413
+ { isSending: { $ne: true } },
414
+ { sendingAt: { $lte: now - sendingTimeout } },
415
+ ];
416
+ } else if (isSendLeaseGuardedUpdate(updateObj)) {
417
+ query.tries = updateObj.leaseTries;
418
+ query.isSending = true;
419
+ query.sendingAt = updateObj.leaseSendingAt;
420
+ query.isCancelled = false;
421
+ query.isFailed = false;
422
+ }
423
+
424
+ const res = await this.collection.updateOne(query, {
425
+ $set: stripInternalUpdateMeta(updateObj),
426
+ });
427
+ if (isSendClaimUpdate(updateObj)) {
428
+ return (res?.modifiedCount || res?.matchedCount || 0) >= 1;
429
+ }
430
+ return (res?.modifiedCount || 0) >= 1;
307
431
  }
308
432
  }
309
433
 
@@ -0,0 +1,100 @@
1
+ export type PostgresQueryResult = {
2
+ rowCount?: number | null | undefined;
3
+ rows?: unknown[] | undefined;
4
+ };
5
+ export type PostgresClient = {
6
+ query: (queryText: string, values?: unknown[]) => Promise<PostgresQueryResult>;
7
+ };
8
+ export type PostgresQueueOption = {
9
+ client: PostgresClient;
10
+ prefix?: string | undefined;
11
+ };
12
+ /** Class representing PostgreSQL Queue for MailTime */
13
+ export class PostgresQueue {
14
+ /**
15
+ * Create a PostgresQueue instance
16
+ * @param {PostgresQueueOption} opts - configuration object
17
+ */
18
+ constructor(opts: PostgresQueueOption);
19
+ name: string;
20
+ client: PostgresClient;
21
+ prefix: any;
22
+ /**
23
+ * @async
24
+ * @memberOf PostgresQueue
25
+ * @name ready
26
+ * @description Wait until PostgreSQL schema is ready
27
+ * @returns {Promise<void 0>}
28
+ */
29
+ ready(): Promise<void>;
30
+ /**
31
+ * @async
32
+ * @memberOf PostgresQueue
33
+ * @name ping
34
+ * @description Check connection to Storage
35
+ * @returns {Promise<object>}
36
+ */
37
+ ping(): Promise<object>;
38
+ /**
39
+ * @memberOf PostgresQueue
40
+ * @name iterate
41
+ * @description iterate over queued tasks passing each to `mailTimeInstance.___dispatch` (the bounded send pool). Postgres reads buffer the full result, so each tick is bounded by `opts.limit` (or 1000 when caller passes `Infinity` / no limit) to keep memory predictable; high-throughput deployments should shard prefixes.
42
+ * @param {{ limit?: number, sendingTimeout?: number }} [opts] - iteration options
43
+ * @returns {Promise<void>}
44
+ */
45
+ iterate(opts?: {
46
+ limit?: number;
47
+ sendingTimeout?: number;
48
+ }): Promise<void>;
49
+ /**
50
+ * @async
51
+ * @memberOf PostgresQueue
52
+ * @name getPendingTo
53
+ * @description get queued task by `to` field (addressee)
54
+ * @param to {string} - email address
55
+ * @param sendAt {number} - timestamp
56
+ * @returns {Promise<object|null>}
57
+ */
58
+ getPendingTo(to: string, sendAt: number): Promise<object | null>;
59
+ /**
60
+ * @async
61
+ * @memberOf PostgresQueue
62
+ * @name push
63
+ * @description push task to the queue/storage
64
+ * @param task {object} - task's object
65
+ * @returns {Promise<void 0>}
66
+ */
67
+ push(task: object): Promise<void>;
68
+ /**
69
+ * @async
70
+ * @memberOf PostgresQueue
71
+ * @name cancel
72
+ * @description cancel scheduled email
73
+ * @param uuid {string} - email's uuid
74
+ * @returns {Promise<boolean>} returns `true` if cancelled or `false` if not found, was sent, or was cancelled previously
75
+ */
76
+ cancel(uuid: string): Promise<boolean>;
77
+ /**
78
+ * @async
79
+ * @memberOf PostgresQueue
80
+ * @name remove
81
+ * @description remove task from queue
82
+ * @param task {object} - task's object
83
+ * @param {{ leaseTries: number, leaseSendingAt: number }} [opts] - lease guard: only remove if this worker still holds the lease (tries + sendingAt match, row not cancelled/failed)
84
+ * @returns {Promise<boolean>} returns `true` if removed or `false` if not found
85
+ */
86
+ remove(task: object, opts?: {
87
+ leaseTries: number;
88
+ leaseSendingAt: number;
89
+ }): Promise<boolean>;
90
+ /**
91
+ * @async
92
+ * @memberOf PostgresQueue
93
+ * @name update
94
+ * @description update task in queue
95
+ * @param task {object} - task's object
96
+ * @param updateObj {object} - fields with new values to update
97
+ * @returns {Promise<boolean>} returns `true` if updated or `false` if not found or no changes was made
98
+ */
99
+ update(task: object, updateObj: object): Promise<boolean>;
100
+ }