@keetanetwork/anchor 0.0.32 → 0.0.34
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/lib/http-server/index.d.ts +7 -1
- package/lib/http-server/index.d.ts.map +1 -1
- package/lib/http-server/index.js +2 -0
- package/lib/http-server/index.js.map +1 -1
- package/lib/queue/common.d.ts +26 -0
- package/lib/queue/common.d.ts.map +1 -0
- package/lib/queue/common.js +47 -0
- package/lib/queue/common.js.map +1 -0
- package/lib/queue/drivers/queue_file.d.ts +17 -0
- package/lib/queue/drivers/queue_file.d.ts.map +1 -0
- package/lib/queue/drivers/queue_file.js +100 -0
- package/lib/queue/drivers/queue_file.js.map +1 -0
- package/lib/queue/drivers/queue_postgres.d.ts +28 -0
- package/lib/queue/drivers/queue_postgres.d.ts.map +1 -0
- package/lib/queue/drivers/queue_postgres.js +360 -0
- package/lib/queue/drivers/queue_postgres.js.map +1 -0
- package/lib/queue/drivers/queue_redis.d.ts +27 -0
- package/lib/queue/drivers/queue_redis.d.ts.map +1 -0
- package/lib/queue/drivers/queue_redis.js +359 -0
- package/lib/queue/drivers/queue_redis.js.map +1 -0
- package/lib/queue/drivers/queue_sqlite3.d.ts +28 -0
- package/lib/queue/drivers/queue_sqlite3.d.ts.map +1 -0
- package/lib/queue/drivers/queue_sqlite3.js +378 -0
- package/lib/queue/drivers/queue_sqlite3.js.map +1 -0
- package/lib/queue/index.d.ts +341 -0
- package/lib/queue/index.d.ts.map +1 -0
- package/lib/queue/index.js +940 -0
- package/lib/queue/index.js.map +1 -0
- package/lib/queue/internal.d.ts +20 -0
- package/lib/queue/internal.d.ts.map +1 -0
- package/lib/queue/internal.js +66 -0
- package/lib/queue/internal.js.map +1 -0
- package/lib/queue/pipeline.d.ts +152 -0
- package/lib/queue/pipeline.d.ts.map +1 -0
- package/lib/queue/pipeline.js +296 -0
- package/lib/queue/pipeline.js.map +1 -0
- package/lib/resolver.d.ts +1 -1
- package/lib/resolver.d.ts.map +1 -1
- package/lib/resolver.js.map +1 -1
- package/lib/utils/asleep.d.ts +2 -0
- package/lib/utils/asleep.d.ts.map +1 -0
- package/lib/utils/asleep.js +3 -0
- package/lib/utils/asleep.js.map +1 -0
- package/lib/utils/defer.d.ts +4 -0
- package/lib/utils/defer.d.ts.map +1 -0
- package/lib/utils/defer.js +3 -0
- package/lib/utils/defer.js.map +1 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/services/asset-movement/common.d.ts +15 -1
- package/services/asset-movement/common.d.ts.map +1 -1
- package/services/asset-movement/common.js +345 -147
- package/services/asset-movement/common.js.map +1 -1
- package/services/asset-movement/lib/location.js +1 -1
- package/services/asset-movement/lib/location.js.map +1 -1
- package/services/fx/client.d.ts +1 -1
- package/services/fx/client.d.ts.map +1 -1
- package/services/fx/client.js +2 -2
- package/services/fx/client.js.map +1 -1
- package/services/fx/common.d.ts +19 -4
- package/services/fx/common.d.ts.map +1 -1
- package/services/fx/common.js +8 -5
- package/services/fx/common.js.map +1 -1
- package/services/fx/server.d.ts +105 -8
- package/services/fx/server.d.ts.map +1 -1
- package/services/fx/server.js +609 -43
- package/services/fx/server.js.map +1 -1
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { __addDisposableResource, __disposeResources } from "tslib";
|
|
2
|
+
import { MethodLogger, ManageStatusUpdates, ConvertStringToRequestID } from '../internal.js';
|
|
3
|
+
import { Errors } from '../common.js';
|
|
4
|
+
import { asleep } from '../../utils/asleep.js';
|
|
5
|
+
export default class KeetaAnchorQueueStorageDriverSQLite3 {
|
|
6
|
+
logger;
|
|
7
|
+
dbInternal = null;
|
|
8
|
+
dbInitializationPromise;
|
|
9
|
+
name = 'KeetaAnchorQueueStorageDriverSQLite3';
|
|
10
|
+
id;
|
|
11
|
+
path = [];
|
|
12
|
+
pathStr;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.id = options?.id ?? crypto.randomUUID();
|
|
15
|
+
this.logger = options?.logger;
|
|
16
|
+
this.dbInternal = options.db;
|
|
17
|
+
this.path = options.path ?? [];
|
|
18
|
+
this.pathStr = ['root', ...this.path].join('.');
|
|
19
|
+
Object.freeze(this.path);
|
|
20
|
+
this.methodLogger('new')?.debug('Initialized SQLite3 queue storage driver with DB:', options.db);
|
|
21
|
+
}
|
|
22
|
+
async initializeDBConnection(db) {
|
|
23
|
+
this.methodLogger('initializeDBConnection')?.debug('Setting DB connection parameters (WAL mode, synchronous=normal)');
|
|
24
|
+
await db.exec(`
|
|
25
|
+
PRAGMA journal_mode = WAL;
|
|
26
|
+
PRAGMA synchronous = NORMAL;
|
|
27
|
+
`);
|
|
28
|
+
db.configure('busyTimeout', 100);
|
|
29
|
+
if (this.dbInitializationPromise) {
|
|
30
|
+
await this.dbInitializationPromise;
|
|
31
|
+
return (db);
|
|
32
|
+
}
|
|
33
|
+
this.methodLogger('initializeDBConnection')?.debug('Initializing DB schema for queue storage driver');
|
|
34
|
+
this.dbInitializationPromise = (async function () {
|
|
35
|
+
await db.exec(`
|
|
36
|
+
CREATE TABLE IF NOT EXISTS queue_entries (
|
|
37
|
+
id TEXT NOT NULL,
|
|
38
|
+
path TEXT NOT NULL,
|
|
39
|
+
request TEXT NOT NULL,
|
|
40
|
+
output TEXT,
|
|
41
|
+
lastError TEXT,
|
|
42
|
+
status TEXT NOT NULL,
|
|
43
|
+
created INTEGER NOT NULL,
|
|
44
|
+
updated INTEGER NOT NULL,
|
|
45
|
+
worker INTEGER,
|
|
46
|
+
failures INTEGER NOT NULL DEFAULT 0,
|
|
47
|
+
PRIMARY KEY (id, path)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
CREATE TABLE IF NOT EXISTS queue_idempotent_keys (
|
|
51
|
+
entry_id TEXT NOT NULL,
|
|
52
|
+
idempotent_id TEXT NOT NULL,
|
|
53
|
+
path TEXT NOT NULL,
|
|
54
|
+
UNIQUE (idempotent_id, path),
|
|
55
|
+
PRIMARY KEY (entry_id, idempotent_id, path),
|
|
56
|
+
FOREIGN KEY (entry_id, path) REFERENCES queue_entries(id, path)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_queue_entries_status ON queue_entries(status);
|
|
60
|
+
CREATE INDEX IF NOT EXISTS idx_queue_entries_updated ON queue_entries(updated);
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_queue_idempotent_keys_idempotent_id ON queue_idempotent_keys(idempotent_id);
|
|
62
|
+
`);
|
|
63
|
+
return (true);
|
|
64
|
+
})();
|
|
65
|
+
await this.dbInitializationPromise;
|
|
66
|
+
return (db);
|
|
67
|
+
}
|
|
68
|
+
methodLogger(method) {
|
|
69
|
+
return (MethodLogger(this.logger, {
|
|
70
|
+
class: 'KeetaAnchorQueueStorageDriverSQLite3',
|
|
71
|
+
file: 'src/lib/queue/drivers/queue_sqlite3.ts',
|
|
72
|
+
method: method,
|
|
73
|
+
instanceID: this.id
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
async runWithBusyHandler(fn) {
|
|
77
|
+
const logger = this.methodLogger('runWithBusyHandler');
|
|
78
|
+
let lastError;
|
|
79
|
+
for (let retry = 0; retry < 100; retry++) {
|
|
80
|
+
if (this.dbInternal === null) {
|
|
81
|
+
this.methodLogger('runWithBusyHandler')?.debug('Aborting DB operation retries because the instance was destroyed');
|
|
82
|
+
if (lastError !== undefined) {
|
|
83
|
+
/*
|
|
84
|
+
* TypeScript does not know what the error is, but it's whatever we caught,
|
|
85
|
+
* so it must be something our caller expects
|
|
86
|
+
*/
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/only-throw-error
|
|
88
|
+
throw (lastError);
|
|
89
|
+
}
|
|
90
|
+
throw (new Error('Aborting because the instance was destroyed'));
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
return (await fn());
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
lastError = error;
|
|
97
|
+
if (error instanceof Error) {
|
|
98
|
+
if (error.message.includes('SQLITE_BUSY') || error.message.includes('SQLITE_LOCKED')) {
|
|
99
|
+
logger?.debug('Database is busy or locked');
|
|
100
|
+
const minBackoff = 100;
|
|
101
|
+
const maxBackoff = 30_000;
|
|
102
|
+
const backoffIntervalSize = Math.min(maxBackoff - minBackoff, (retry + 50) ** 2);
|
|
103
|
+
const backoff = Math.round((Math.random() * backoffIntervalSize)) + minBackoff;
|
|
104
|
+
this.methodLogger('runWithBusyHandler')?.debug(`Retrying DB operation in ${backoff}ms (retry #${retry}) (interval size: ${backoffIntervalSize}ms, min: ${minBackoff}ms, max: ${maxBackoff}ms) from`, new Error().stack);
|
|
105
|
+
await asleep(backoff);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
throw (error);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
throw (lastError);
|
|
113
|
+
}
|
|
114
|
+
newDBConnection() {
|
|
115
|
+
if (this.dbInternal === null) {
|
|
116
|
+
throw (new Error('Database connection is not available'));
|
|
117
|
+
}
|
|
118
|
+
return ((async () => {
|
|
119
|
+
return (await this.runWithBusyHandler(async () => {
|
|
120
|
+
if (this.dbInternal === null) {
|
|
121
|
+
throw (new Error('Database connection is not available'));
|
|
122
|
+
}
|
|
123
|
+
this.methodLogger('newDBConnection')?.debug('Opening new DB connection');
|
|
124
|
+
const db = await this.dbInternal();
|
|
125
|
+
return ({
|
|
126
|
+
db: await this.initializeDBConnection(db),
|
|
127
|
+
[Symbol.asyncDispose]: async () => {
|
|
128
|
+
this.methodLogger('dbConnectionDispose')?.debug('Closing DB connection');
|
|
129
|
+
await db.close();
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}));
|
|
133
|
+
})());
|
|
134
|
+
}
|
|
135
|
+
async dbTransaction(className, fn) {
|
|
136
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
137
|
+
try {
|
|
138
|
+
const dbConnection = __addDisposableResource(env_1, await this.newDBConnection(), true);
|
|
139
|
+
const db = dbConnection.db;
|
|
140
|
+
const logger = this.methodLogger(className);
|
|
141
|
+
const result = await this.runWithBusyHandler(async function () {
|
|
142
|
+
logger?.debug('Starting DB transaction');
|
|
143
|
+
await db.run('BEGIN TRANSACTION');
|
|
144
|
+
logger?.debug('DB transaction started');
|
|
145
|
+
try {
|
|
146
|
+
const retval = await fn(db, logger);
|
|
147
|
+
logger?.debug('Committing DB transaction');
|
|
148
|
+
await db.run('COMMIT');
|
|
149
|
+
logger?.debug('DB transaction committed');
|
|
150
|
+
return (retval);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
try {
|
|
154
|
+
logger?.debug('Rolling back DB transaction due to error:', error);
|
|
155
|
+
await db.run('ROLLBACK');
|
|
156
|
+
logger?.debug('DB transaction rolled back');
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
logger?.debug('Error rolling back DB transaction !!');
|
|
160
|
+
/* Ignore rollback errors */
|
|
161
|
+
}
|
|
162
|
+
throw (error);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
return (result);
|
|
166
|
+
}
|
|
167
|
+
catch (e_1) {
|
|
168
|
+
env_1.error = e_1;
|
|
169
|
+
env_1.hasError = true;
|
|
170
|
+
}
|
|
171
|
+
finally {
|
|
172
|
+
const result_1 = __disposeResources(env_1);
|
|
173
|
+
if (result_1)
|
|
174
|
+
await result_1;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async add(request, info) {
|
|
178
|
+
return (await this.dbTransaction('add', async (db, logger) => {
|
|
179
|
+
let entryID = ConvertStringToRequestID(info?.id);
|
|
180
|
+
if (entryID) {
|
|
181
|
+
const existingEntry = await db.get('SELECT id FROM queue_entries WHERE id = ? AND path = ?', entryID, this.pathStr);
|
|
182
|
+
if (existingEntry) {
|
|
183
|
+
logger?.debug(`Request with id ${String(entryID)} already exists, ignoring`);
|
|
184
|
+
return (entryID);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const idempotentIDs = info?.idempotentKeys;
|
|
188
|
+
if (idempotentIDs) {
|
|
189
|
+
const matchingIdempotentEntries = new Set();
|
|
190
|
+
for (const idempotentID of idempotentIDs) {
|
|
191
|
+
const idempotentEntryExists = await db.get('SELECT idempotent_id FROM queue_idempotent_keys WHERE idempotent_id = ? AND path = ?', idempotentID, this.pathStr);
|
|
192
|
+
if (idempotentEntryExists) {
|
|
193
|
+
matchingIdempotentEntries.add(idempotentID);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (matchingIdempotentEntries.size !== 0) {
|
|
197
|
+
throw (new Errors.IdempotentExistsError('One or more idempotent entries already exist in the queue', matchingIdempotentEntries));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
entryID ??= ConvertStringToRequestID(crypto.randomUUID());
|
|
201
|
+
logger?.debug(`Enqueuing request with id ${String(entryID)}`);
|
|
202
|
+
const currentTime = Date.now();
|
|
203
|
+
const requestJSON = JSON.stringify(request);
|
|
204
|
+
/**
|
|
205
|
+
* The status to use for the new entry
|
|
206
|
+
*/
|
|
207
|
+
const status = info?.status ?? 'pending';
|
|
208
|
+
try {
|
|
209
|
+
await db.run(`INSERT INTO queue_entries (id, path, request, output, lastError, status, created, updated, worker, failures)
|
|
210
|
+
VALUES (?, ?, ?, NULL, NULL, ?, ?, ?, NULL, 0)`, entryID, this.pathStr, requestJSON, status, currentTime, currentTime);
|
|
211
|
+
if (idempotentIDs && idempotentIDs.size > 0) {
|
|
212
|
+
for (const idempotentID of idempotentIDs) {
|
|
213
|
+
await db.run('INSERT INTO queue_idempotent_keys (entry_id, path, idempotent_id) VALUES (?, ?, ?)', entryID, this.pathStr, idempotentID);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
if (error instanceof Error && error.message.includes('UNIQUE constraint failed') && idempotentIDs) {
|
|
219
|
+
throw (new Errors.IdempotentExistsError('One or more idempotent entries already exist in the queue', idempotentIDs));
|
|
220
|
+
}
|
|
221
|
+
throw (error);
|
|
222
|
+
}
|
|
223
|
+
return (entryID);
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
async setStatus(id, status, ancillary) {
|
|
227
|
+
return (await this.dbTransaction('setStatus', async (db, logger) => {
|
|
228
|
+
const existingEntry = await db.get('SELECT status, failures, lastError, output FROM queue_entries WHERE id = ? AND path = ?', id, this.pathStr);
|
|
229
|
+
if (!existingEntry) {
|
|
230
|
+
throw (new Error(`Request with ID ${String(id)} not found`));
|
|
231
|
+
}
|
|
232
|
+
const changedData = ManageStatusUpdates(id, {
|
|
233
|
+
status: existingEntry.status,
|
|
234
|
+
failures: existingEntry.failures
|
|
235
|
+
}, status, ancillary, logger);
|
|
236
|
+
const newEntry = {
|
|
237
|
+
...existingEntry,
|
|
238
|
+
...changedData
|
|
239
|
+
};
|
|
240
|
+
const oldStatus = ancillary?.oldStatus;
|
|
241
|
+
const currentTime = newEntry.updated?.getTime();
|
|
242
|
+
const workerValue = newEntry.worker;
|
|
243
|
+
const newFailures = newEntry.failures;
|
|
244
|
+
const newLastError = newEntry.lastError !== undefined ? newEntry.lastError : existingEntry.lastError;
|
|
245
|
+
const newOutput = newEntry.output !== undefined ? JSON.stringify(newEntry.output) : null;
|
|
246
|
+
if (currentTime === undefined || workerValue === undefined || newFailures === undefined) {
|
|
247
|
+
throw (new Error('Internal error: Missing updated data for status update'));
|
|
248
|
+
}
|
|
249
|
+
let updateQuery;
|
|
250
|
+
let updateParams;
|
|
251
|
+
if (oldStatus) {
|
|
252
|
+
updateQuery = `UPDATE queue_entries
|
|
253
|
+
SET status = ?, updated = ?, worker = ?, failures = ?, lastError = ?, output = ?
|
|
254
|
+
WHERE id = ? AND path = ? AND status = ?`;
|
|
255
|
+
updateParams = [status, currentTime, workerValue, newFailures, newLastError, newOutput, id, this.pathStr, oldStatus];
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
updateQuery = `UPDATE queue_entries
|
|
259
|
+
SET status = ?, updated = ?, worker = ?, failures = ?, lastError = ?, output = ?
|
|
260
|
+
WHERE id = ? AND path = ?`;
|
|
261
|
+
updateParams = [status, currentTime, workerValue, newFailures, newLastError, newOutput, id, this.pathStr];
|
|
262
|
+
}
|
|
263
|
+
const result = await db.run(updateQuery, ...updateParams);
|
|
264
|
+
if (oldStatus && result.changes === 0) {
|
|
265
|
+
const currentEntry = await db.get('SELECT status FROM queue_entries WHERE id = ? AND path = ?', id, this.pathStr);
|
|
266
|
+
if (currentEntry) {
|
|
267
|
+
throw (new Errors.IncorrectStateAssertedError(id, oldStatus, currentEntry.status));
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
throw (new Error(`Request with ID ${String(id)} not found`));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}));
|
|
274
|
+
}
|
|
275
|
+
async get(id) {
|
|
276
|
+
return (await this.dbTransaction('get', async (db) => {
|
|
277
|
+
const row = await db.get(`SELECT id, request, output, lastError, status, created, updated, worker, failures
|
|
278
|
+
FROM queue_entries WHERE id = ? AND path = ?`, id, this.pathStr);
|
|
279
|
+
if (!row) {
|
|
280
|
+
return (null);
|
|
281
|
+
}
|
|
282
|
+
const idempotentRows = await db.all('SELECT idempotent_id FROM queue_idempotent_keys WHERE entry_id = ? AND path = ?', id, this.pathStr);
|
|
283
|
+
const idempotentKeys = idempotentRows.length > 0
|
|
284
|
+
? new Set(idempotentRows.map(function (idempotentRow) {
|
|
285
|
+
return (ConvertStringToRequestID(idempotentRow.idempotent_id));
|
|
286
|
+
}))
|
|
287
|
+
: undefined;
|
|
288
|
+
return ({
|
|
289
|
+
id: ConvertStringToRequestID(row.id),
|
|
290
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
291
|
+
request: JSON.parse(row.request),
|
|
292
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
293
|
+
output: row.output ? JSON.parse(row.output) : null,
|
|
294
|
+
lastError: row.lastError,
|
|
295
|
+
status: row.status,
|
|
296
|
+
created: new Date(row.created),
|
|
297
|
+
updated: new Date(row.updated),
|
|
298
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
299
|
+
worker: row.worker,
|
|
300
|
+
failures: row.failures,
|
|
301
|
+
idempotentKeys: idempotentKeys
|
|
302
|
+
});
|
|
303
|
+
}));
|
|
304
|
+
}
|
|
305
|
+
async query(filter) {
|
|
306
|
+
return (await this.dbTransaction('query', async (db, logger) => {
|
|
307
|
+
logger?.debug(`Querying queue with id ${this.id} with filter:`, filter);
|
|
308
|
+
const conditions = [];
|
|
309
|
+
const params = [];
|
|
310
|
+
conditions.push('path = ?');
|
|
311
|
+
params.push(this.pathStr);
|
|
312
|
+
if (filter?.status) {
|
|
313
|
+
conditions.push('status = ?');
|
|
314
|
+
params.push(filter.status);
|
|
315
|
+
}
|
|
316
|
+
if (filter?.updatedBefore) {
|
|
317
|
+
conditions.push('updated < ?');
|
|
318
|
+
params.push(filter.updatedBefore.getTime());
|
|
319
|
+
}
|
|
320
|
+
let query = 'SELECT id, request, output, lastError, status, created, updated, worker, failures FROM queue_entries';
|
|
321
|
+
if (conditions.length > 0) {
|
|
322
|
+
query += ' WHERE ' + conditions.join(' AND ');
|
|
323
|
+
}
|
|
324
|
+
if (filter?.limit !== undefined) {
|
|
325
|
+
query += ' LIMIT ?';
|
|
326
|
+
params.push(filter.limit);
|
|
327
|
+
}
|
|
328
|
+
const rows = await db.all(query, ...params);
|
|
329
|
+
const entries = [];
|
|
330
|
+
for (const row of rows) {
|
|
331
|
+
const idempotentRows = await db.all('SELECT idempotent_id FROM queue_idempotent_keys WHERE entry_id = ? AND path = ?', row.id, this.pathStr);
|
|
332
|
+
const idempotentKeys = idempotentRows.length > 0
|
|
333
|
+
? new Set(idempotentRows.map(function (idempotentRow) {
|
|
334
|
+
return (ConvertStringToRequestID(idempotentRow.idempotent_id));
|
|
335
|
+
}))
|
|
336
|
+
: undefined;
|
|
337
|
+
entries.push({
|
|
338
|
+
id: ConvertStringToRequestID(row.id),
|
|
339
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
340
|
+
request: JSON.parse(row.request),
|
|
341
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
342
|
+
output: row.output ? JSON.parse(row.output) : null,
|
|
343
|
+
lastError: row.lastError,
|
|
344
|
+
status: row.status,
|
|
345
|
+
created: new Date(row.created),
|
|
346
|
+
updated: new Date(row.updated),
|
|
347
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
348
|
+
worker: row.worker,
|
|
349
|
+
failures: row.failures,
|
|
350
|
+
idempotentKeys: idempotentKeys
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
logger?.debug(`Queried queue with id ${this.id} with filter:`, filter, '-- found', entries.length, 'entries');
|
|
354
|
+
return (entries);
|
|
355
|
+
}));
|
|
356
|
+
}
|
|
357
|
+
async partition(path) {
|
|
358
|
+
this.methodLogger('partition')?.debug(`Creating partitioned queue storage driver for path: ${path}`);
|
|
359
|
+
if (this.dbInternal === null) {
|
|
360
|
+
throw (new Error('Asked to partition the instance, but the instance has been destroyed'));
|
|
361
|
+
}
|
|
362
|
+
const retval = new KeetaAnchorQueueStorageDriverSQLite3({
|
|
363
|
+
id: `${this.id}::${path}`,
|
|
364
|
+
logger: this.logger,
|
|
365
|
+
db: this.dbInternal,
|
|
366
|
+
path: [...this.path, path]
|
|
367
|
+
});
|
|
368
|
+
return (retval);
|
|
369
|
+
}
|
|
370
|
+
async destroy() {
|
|
371
|
+
this.methodLogger('destroy')?.debug('Destroying instance');
|
|
372
|
+
this.dbInternal = null;
|
|
373
|
+
}
|
|
374
|
+
async [Symbol.asyncDispose]() {
|
|
375
|
+
return (await this.destroy());
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
//# sourceMappingURL=queue_sqlite3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue_sqlite3.js","sourceRoot":"","sources":["../../../../src/lib/queue/drivers/queue_sqlite3.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tKeetaAnchorQueueStorageDriver,\n\tKeetaAnchorQueueStorageDriverConstructor,\n\tKeetaAnchorQueueRequest,\n\tKeetaAnchorQueueRequestID,\n\tKeetaAnchorQueueEntry,\n\tKeetaAnchorQueueEntryExtra,\n\tKeetaAnchorQueueEntryAncillaryData,\n\tKeetaAnchorQueueStatus,\n\tKeetaAnchorQueueFilter,\n\tKeetaAnchorQueueWorkerID\n} from '../index.ts';\nimport {\n\tMethodLogger,\n\tManageStatusUpdates,\n\tConvertStringToRequestID\n} from '../internal.js';\nimport { Errors } from '../common.js';\n\nimport { asleep } from '../../utils/asleep.js';\n\nimport type { Logger } from '../../log/index.ts';\nimport type { JSONSerializable } from '../../utils/json.js';\n\nimport type * as sqlite from 'sqlite';\n\ntype QueueEntryRow = {\n\tid: string;\n\trequest: string;\n\toutput: string | null;\n\tlastError: string | null;\n\tstatus: KeetaAnchorQueueStatus;\n\tcreated: number;\n\tupdated: number;\n\tworker: number | null;\n\tfailures: number;\n};\n\ntype IdempotentRow = {\n\tidempotent_id: string;\n};\n\nexport default class KeetaAnchorQueueStorageDriverSQLite3<QueueRequest extends JSONSerializable = JSONSerializable, QueueResult extends JSONSerializable = JSONSerializable> implements KeetaAnchorQueueStorageDriver<QueueRequest, QueueResult> {\n\tprivate readonly logger: Logger | undefined;\n\tprivate dbInternal: (() => Promise<sqlite.Database>) | null = null;\n\tprivate dbInitializationPromise?: Promise<boolean>;\n\n\treadonly name = 'KeetaAnchorQueueStorageDriverSQLite3';\n\treadonly id: string;\n\treadonly path: string[] = [];\n\tprivate readonly pathStr: string;\n\n\tconstructor(options: NonNullable<ConstructorParameters<KeetaAnchorQueueStorageDriverConstructor<QueueRequest, QueueResult>>[0]> & { db: () => Promise<sqlite.Database>; }) {\n\t\tthis.id = options?.id ?? crypto.randomUUID();\n\t\tthis.logger = options?.logger;\n\t\tthis.dbInternal = options.db;\n\t\tthis.path = options.path ?? [];\n\t\tthis.pathStr = ['root', ...this.path].join('.');\n\t\tObject.freeze(this.path);\n\n\t\tthis.methodLogger('new')?.debug('Initialized SQLite3 queue storage driver with DB:', options.db);\n\t}\n\n\tprivate async initializeDBConnection(db: sqlite.Database): Promise<sqlite.Database> {\n\t\tthis.methodLogger('initializeDBConnection')?.debug('Setting DB connection parameters (WAL mode, synchronous=normal)');\n\t\tawait db.exec(`\n\t\t\tPRAGMA journal_mode = WAL;\n\t\t\tPRAGMA synchronous = NORMAL;\n\t\t`);\n\n\t\tdb.configure('busyTimeout', 100);\n\n\t\tif (this.dbInitializationPromise) {\n\t\t\tawait this.dbInitializationPromise;\n\t\t\treturn(db);\n\t\t}\n\n\t\tthis.methodLogger('initializeDBConnection')?.debug('Initializing DB schema for queue storage driver');\n\t\tthis.dbInitializationPromise = (async function() {\n\t\t\tawait db.exec(`\n\t\t\t\tCREATE TABLE IF NOT EXISTS queue_entries (\n\t\t\t\t\tid TEXT NOT NULL,\n\t\t\t\t\tpath TEXT NOT NULL,\n\t\t\t\t\trequest TEXT NOT NULL,\n\t\t\t\t\toutput TEXT,\n\t\t\t\t\tlastError TEXT,\n\t\t\t\t\tstatus TEXT NOT NULL,\n\t\t\t\t\tcreated INTEGER NOT NULL,\n\t\t\t\t\tupdated INTEGER NOT NULL,\n\t\t\t\t\tworker INTEGER,\n\t\t\t\t\tfailures INTEGER NOT NULL DEFAULT 0,\n\t\t\t\t\tPRIMARY KEY (id, path)\n\t\t\t\t);\n\n\t\t\t\tCREATE TABLE IF NOT EXISTS queue_idempotent_keys (\n\t\t\t\t\tentry_id TEXT NOT NULL,\n\t\t\t\t\tidempotent_id TEXT NOT NULL,\n\t\t\t\t\tpath TEXT NOT NULL,\n\t\t\t\t\tUNIQUE (idempotent_id, path),\n\t\t\t\t\tPRIMARY KEY (entry_id, idempotent_id, path),\n\t\t\t\t\tFOREIGN KEY (entry_id, path) REFERENCES queue_entries(id, path)\n\t\t\t\t);\n\n\t\t\t\tCREATE INDEX IF NOT EXISTS idx_queue_entries_status ON queue_entries(status);\n\t\t\t\tCREATE INDEX IF NOT EXISTS idx_queue_entries_updated ON queue_entries(updated);\n\t\t\t\tCREATE INDEX IF NOT EXISTS idx_queue_idempotent_keys_idempotent_id ON queue_idempotent_keys(idempotent_id);\n\t\t\t`);\n\n\t\t\treturn(true);\n\t\t})();\n\n\t\tawait this.dbInitializationPromise;\n\n\t\treturn(db);\n\t}\n\n\tprivate methodLogger(method: string): Logger | undefined {\n\t\treturn(MethodLogger(this.logger, {\n\t\t\tclass: 'KeetaAnchorQueueStorageDriverSQLite3',\n\t\t\tfile: 'src/lib/queue/drivers/queue_sqlite3.ts',\n\t\t\tmethod: method,\n\t\t\tinstanceID: this.id\n\t\t}));\n\t}\n\n\tprivate async runWithBusyHandler<T>(fn: () => Promise<T>): Promise<T> {\n\t\tconst logger = this.methodLogger('runWithBusyHandler');\n\n\t\tlet lastError: unknown;\n\t\tfor (let retry = 0; retry < 100; retry++) {\n\t\t\tif (this.dbInternal === null) {\n\t\t\t\tthis.methodLogger('runWithBusyHandler')?.debug('Aborting DB operation retries because the instance was destroyed');\n\n\t\t\t\tif (lastError !== undefined) {\n\t\t\t\t\t/*\n\t\t\t\t\t * TypeScript does not know what the error is, but it's whatever we caught,\n\t\t\t\t\t * so it must be something our caller expects\n\t\t\t\t\t */\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/only-throw-error\n\t\t\t\t\tthrow(lastError);\n\t\t\t\t}\n\t\t\t\tthrow(new Error('Aborting because the instance was destroyed'));\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\treturn(await fn());\n\t\t\t} catch (error: unknown) {\n\t\t\t\tlastError = error;\n\n\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\tif (error.message.includes('SQLITE_BUSY') || error.message.includes('SQLITE_LOCKED')) {\n\t\t\t\t\t\tlogger?.debug('Database is busy or locked');\n\n\t\t\t\t\t\tconst minBackoff = 100;\n\t\t\t\t\t\tconst maxBackoff = 30_000;\n\t\t\t\t\t\tconst backoffIntervalSize = Math.min(maxBackoff - minBackoff, (retry + 50) ** 2);\n\t\t\t\t\t\tconst backoff = Math.round((Math.random() * backoffIntervalSize)) + minBackoff;\n\n\t\t\t\t\t\tthis.methodLogger('runWithBusyHandler')?.debug(`Retrying DB operation in ${backoff}ms (retry #${retry}) (interval size: ${backoffIntervalSize}ms, min: ${minBackoff}ms, max: ${maxBackoff}ms) from`, new Error().stack);\n\t\t\t\t\t\tawait asleep(backoff);\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthrow(error);\n\t\t\t}\n\t\t}\n\t\tthrow(lastError);\n\t}\n\n\tprivate newDBConnection(): Promise<{ db: sqlite.Database; [Symbol.asyncDispose]: () => Promise<void>; }> {\n\t\tif (this.dbInternal === null) {\n\t\t\tthrow(new Error('Database connection is not available'));\n\t\t}\n\n\t\treturn((async () => {\n\t\t\treturn(await this.runWithBusyHandler(async () => {\n\t\t\t\tif (this.dbInternal === null) {\n\t\t\t\t\tthrow(new Error('Database connection is not available'));\n\t\t\t\t}\n\n\t\t\t\tthis.methodLogger('newDBConnection')?.debug('Opening new DB connection');\n\t\t\t\tconst db = await this.dbInternal();\n\n\t\t\t\treturn({\n\t\t\t\t\tdb: await this.initializeDBConnection(db),\n\t\t\t\t\t[Symbol.asyncDispose]: async (): Promise<void> => {\n\t\t\t\t\t\tthis.methodLogger('dbConnectionDispose')?.debug('Closing DB connection');\n\t\t\t\t\t\tawait db.close();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}));\n\t\t})());\n\t}\n\n\tprivate async dbTransaction<T>(className: string, fn: (db: sqlite.Database, logger: Logger | undefined) => Promise<T>): Promise<T> {\n\t\tawait using dbConnection = await this.newDBConnection();\n\t\tconst db = dbConnection.db;\n\t\tconst logger = this.methodLogger(className);\n\n\t\tconst result = await this.runWithBusyHandler(async function() {\n\t\t\tlogger?.debug('Starting DB transaction');\n\t\t\tawait db.run('BEGIN TRANSACTION');\n\t\t\tlogger?.debug('DB transaction started');\n\n\t\t\ttry {\n\t\t\t\tconst retval = await fn(db, logger);\n\n\t\t\t\tlogger?.debug('Committing DB transaction');\n\t\t\t\tawait db.run('COMMIT');\n\t\t\t\tlogger?.debug('DB transaction committed');\n\n\t\t\t\treturn(retval);\n\t\t\t} catch (error: unknown) {\n\t\t\t\ttry {\n\t\t\t\t\tlogger?.debug('Rolling back DB transaction due to error:', error);\n\t\t\t\t\tawait db.run('ROLLBACK');\n\t\t\t\t\tlogger?.debug('DB transaction rolled back');\n\t\t\t\t} catch {\n\t\t\t\t\tlogger?.debug('Error rolling back DB transaction !!');\n\t\t\t\t\t/* Ignore rollback errors */\n\t\t\t\t}\n\t\t\t\tthrow(error);\n\t\t\t}\n\t\t});\n\n\t\treturn(result);\n\t}\n\n\tasync add(request: KeetaAnchorQueueRequest<QueueRequest>, info?: KeetaAnchorQueueEntryExtra): Promise<KeetaAnchorQueueRequestID> {\n\t\treturn(await this.dbTransaction('add', async (db, logger): Promise<KeetaAnchorQueueRequestID> => {\n\t\t\tlet entryID = ConvertStringToRequestID(info?.id);\n\t\t\tif (entryID) {\n\t\t\t\tconst existingEntry = await db.get<{ id: string }>('SELECT id FROM queue_entries WHERE id = ? AND path = ?', entryID, this.pathStr);\n\t\t\t\tif (existingEntry) {\n\t\t\t\t\tlogger?.debug(`Request with id ${String(entryID)} already exists, ignoring`);\n\t\t\t\t\treturn(entryID);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst idempotentIDs = info?.idempotentKeys;\n\t\t\tif (idempotentIDs) {\n\t\t\t\tconst matchingIdempotentEntries = new Set<KeetaAnchorQueueRequestID>();\n\t\t\t\tfor (const idempotentID of idempotentIDs) {\n\t\t\t\t\tconst idempotentEntryExists = await db.get<IdempotentRow>(\n\t\t\t\t\t\t'SELECT idempotent_id FROM queue_idempotent_keys WHERE idempotent_id = ? AND path = ?',\n\t\t\t\t\t\tidempotentID, this.pathStr\n\t\t\t\t\t);\n\t\t\t\t\tif (idempotentEntryExists) {\n\t\t\t\t\t\tmatchingIdempotentEntries.add(idempotentID);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (matchingIdempotentEntries.size !== 0) {\n\t\t\t\t\tthrow(new Errors.IdempotentExistsError('One or more idempotent entries already exist in the queue', matchingIdempotentEntries));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tentryID ??= ConvertStringToRequestID(crypto.randomUUID());\n\n\t\t\tlogger?.debug(`Enqueuing request with id ${String(entryID)}`);\n\n\t\t\tconst currentTime = Date.now();\n\t\t\tconst requestJSON = JSON.stringify(request);\n\n\t\t\t/**\n\t\t\t * The status to use for the new entry\n\t\t\t */\n\t\t\tconst status = info?.status ?? 'pending';\n\n\t\t\ttry {\n\t\t\t\tawait db.run(\n\t\t\t\t\t`INSERT INTO queue_entries (id, path, request, output, lastError, status, created, updated, worker, failures)\n\t\t\t\t\t VALUES (?, ?, ?, NULL, NULL, ?, ?, ?, NULL, 0)`,\n\t\t\t\t\tentryID,\n\t\t\t\t\tthis.pathStr,\n\t\t\t\t\trequestJSON,\n\t\t\t\t\tstatus,\n\t\t\t\t\tcurrentTime,\n\t\t\t\t\tcurrentTime\n\t\t\t\t);\n\n\t\t\t\tif (idempotentIDs && idempotentIDs.size > 0) {\n\t\t\t\t\tfor (const idempotentID of idempotentIDs) {\n\t\t\t\t\t\tawait db.run('INSERT INTO queue_idempotent_keys (entry_id, path, idempotent_id) VALUES (?, ?, ?)', entryID, this.pathStr, idempotentID);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error: unknown) {\n\t\t\t\tif (error instanceof Error && error.message.includes('UNIQUE constraint failed') && idempotentIDs) {\n\t\t\t\t\tthrow(new Errors.IdempotentExistsError('One or more idempotent entries already exist in the queue', idempotentIDs));\n\t\t\t\t}\n\t\t\t\tthrow(error);\n\t\t\t}\n\n\t\t\treturn(entryID);\n\t\t}));\n\t}\n\n\tasync setStatus(id: KeetaAnchorQueueRequestID, status: KeetaAnchorQueueStatus, ancillary?: KeetaAnchorQueueEntryAncillaryData<QueueResult>): Promise<void> {\n\t\treturn(await this.dbTransaction('setStatus', async (db, logger): Promise<void> => {\n\t\t\tconst existingEntry = await db.get<{ status: KeetaAnchorQueueStatus; failures: number; lastError: string | null; output: string | null }>('SELECT status, failures, lastError, output FROM queue_entries WHERE id = ? AND path = ?', id, this.pathStr);\n\t\t\tif (!existingEntry) {\n\t\t\t\tthrow(new Error(`Request with ID ${String(id)} not found`));\n\t\t\t}\n\n\t\t\tconst changedData = ManageStatusUpdates<QueueResult>(id, {\n\t\t\t\tstatus: existingEntry.status,\n\t\t\t\tfailures: existingEntry.failures\n\t\t\t}, status, ancillary, logger);\n\n\t\t\tconst newEntry = {\n\t\t\t\t...existingEntry,\n\t\t\t\t...changedData\n\t\t\t};\n\n\t\t\tconst oldStatus = ancillary?.oldStatus;\n\t\t\tconst currentTime = newEntry.updated?.getTime();\n\t\t\tconst workerValue = newEntry.worker;\n\t\t\tconst newFailures = newEntry.failures;\n\t\t\tconst newLastError = newEntry.lastError !== undefined ? newEntry.lastError : existingEntry.lastError;\n\t\t\tconst newOutput = newEntry.output !== undefined ? JSON.stringify(newEntry.output) : null;\n\n\t\t\tif (currentTime === undefined || workerValue === undefined || newFailures === undefined) {\n\t\t\t\tthrow(new Error('Internal error: Missing updated data for status update'));\n\t\t\t}\n\n\t\t\tlet updateQuery: string;\n\t\t\tlet updateParams: (KeetaAnchorQueueRequestID | string | number | null)[];\n\n\t\t\tif (oldStatus) {\n\t\t\t\tupdateQuery = `UPDATE queue_entries\n\t\t\t\t SET status = ?, updated = ?, worker = ?, failures = ?, lastError = ?, output = ?\n\t\t\t\t WHERE id = ? AND path = ? AND status = ?`;\n\t\t\t\tupdateParams = [status, currentTime, workerValue, newFailures, newLastError, newOutput, id, this.pathStr, oldStatus];\n\t\t\t} else {\n\t\t\t\tupdateQuery = `UPDATE queue_entries\n\t\t\t\t SET status = ?, updated = ?, worker = ?, failures = ?, lastError = ?, output = ?\n\t\t\t\t WHERE id = ? AND path = ?`;\n\t\t\t\tupdateParams = [status, currentTime, workerValue, newFailures, newLastError, newOutput, id, this.pathStr];\n\t\t\t}\n\n\t\t\tconst result = await db.run(updateQuery, ...updateParams);\n\n\t\t\tif (oldStatus && result.changes === 0) {\n\t\t\t\tconst currentEntry = await db.get<{ status: KeetaAnchorQueueStatus }>('SELECT status FROM queue_entries WHERE id = ? AND path = ?', id, this.pathStr);\n\t\t\t\tif (currentEntry) {\n\t\t\t\t\tthrow(new Errors.IncorrectStateAssertedError(id, oldStatus, currentEntry.status));\n\t\t\t\t} else {\n\t\t\t\t\tthrow(new Error(`Request with ID ${String(id)} not found`));\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\t}\n\n\tasync get(id: KeetaAnchorQueueRequestID): Promise<KeetaAnchorQueueEntry<QueueRequest, QueueResult> | null> {\n\t\treturn(await this.dbTransaction('get', async (db): Promise<KeetaAnchorQueueEntry<QueueRequest, QueueResult> | null> => {\n\t\t\tconst row = await db.get<QueueEntryRow>(\n\t\t\t\t`SELECT id, request, output, lastError, status, created, updated, worker, failures\n\t\t\t\t FROM queue_entries WHERE id = ? AND path = ?`,\n\t\t\t\tid, this.pathStr\n\t\t\t);\n\n\t\t\tif (!row) {\n\t\t\t\treturn(null);\n\t\t\t}\n\n\t\t\tconst idempotentRows = await db.all<IdempotentRow[]>(\n\t\t\t\t'SELECT idempotent_id FROM queue_idempotent_keys WHERE entry_id = ? AND path = ?',\n\t\t\t\tid, this.pathStr\n\t\t\t);\n\n\t\t\tconst idempotentKeys = idempotentRows.length > 0\n\t\t\t\t? new Set(idempotentRows.map(function(idempotentRow: IdempotentRow) {\n\t\t\t\t\treturn(ConvertStringToRequestID(idempotentRow.idempotent_id));\n\t\t\t\t}))\n\t\t\t\t: undefined;\n\n\t\t\treturn({\n\t\t\t\tid: ConvertStringToRequestID(row.id),\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\t\trequest: JSON.parse(row.request) as QueueRequest,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\t\toutput: row.output ? JSON.parse(row.output) as QueueResult : null,\n\t\t\t\tlastError: row.lastError,\n\t\t\t\tstatus: row.status,\n\t\t\t\tcreated: new Date(row.created),\n\t\t\t\tupdated: new Date(row.updated),\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\t\tworker: row.worker as unknown as KeetaAnchorQueueWorkerID | null,\n\t\t\t\tfailures: row.failures,\n\t\t\t\tidempotentKeys: idempotentKeys\n\t\t\t});\n\t\t}));\n\t}\n\n\tasync query(filter?: KeetaAnchorQueueFilter): Promise<KeetaAnchorQueueEntry<QueueRequest, QueueResult>[]> {\n\t\treturn(await this.dbTransaction('query', async (db, logger): Promise<KeetaAnchorQueueEntry<QueueRequest, QueueResult>[]> => {\n\t\t\tlogger?.debug(`Querying queue with id ${this.id} with filter:`, filter);\n\n\t\t\tconst conditions: string[] = [];\n\t\t\tconst params: (string | number)[] = [];\n\n\t\t\tconditions.push('path = ?');\n\t\t\tparams.push(this.pathStr);\n\n\t\t\tif (filter?.status) {\n\t\t\t\tconditions.push('status = ?');\n\t\t\t\tparams.push(filter.status);\n\t\t\t}\n\n\t\t\tif (filter?.updatedBefore) {\n\t\t\t\tconditions.push('updated < ?');\n\t\t\t\tparams.push(filter.updatedBefore.getTime());\n\t\t\t}\n\n\t\t\tlet query = 'SELECT id, request, output, lastError, status, created, updated, worker, failures FROM queue_entries';\n\n\t\t\tif (conditions.length > 0) {\n\t\t\t\tquery += ' WHERE ' + conditions.join(' AND ');\n\t\t\t}\n\n\t\t\tif (filter?.limit !== undefined) {\n\t\t\t\tquery += ' LIMIT ?';\n\t\t\t\tparams.push(filter.limit);\n\t\t\t}\n\n\t\t\tconst rows = await db.all<QueueEntryRow[]>(query, ...params);\n\n\t\t\tconst entries: KeetaAnchorQueueEntry<QueueRequest, QueueResult>[] = [];\n\n\t\t\tfor (const row of rows) {\n\t\t\t\tconst idempotentRows = await db.all<IdempotentRow[]>(\n\t\t\t\t\t'SELECT idempotent_id FROM queue_idempotent_keys WHERE entry_id = ? AND path = ?',\n\t\t\t\t\trow.id, this.pathStr\n\t\t\t\t);\n\n\t\t\t\tconst idempotentKeys = idempotentRows.length > 0\n\t\t\t\t\t? new Set(idempotentRows.map(function(idempotentRow: IdempotentRow) {\n\t\t\t\t\t\treturn(ConvertStringToRequestID(idempotentRow.idempotent_id));\n\t\t\t\t\t}))\n\t\t\t\t\t: undefined;\n\n\t\t\t\tentries.push({\n\t\t\t\t\tid: ConvertStringToRequestID(row.id),\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\t\t\trequest: JSON.parse(row.request) as QueueRequest,\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\t\t\toutput: row.output ? JSON.parse(row.output) as QueueResult : null,\n\t\t\t\t\tlastError: row.lastError,\n\t\t\t\t\tstatus: row.status,\n\t\t\t\t\tcreated: new Date(row.created),\n\t\t\t\t\tupdated: new Date(row.updated),\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\t\t\tworker: row.worker as unknown as KeetaAnchorQueueWorkerID | null,\n\t\t\t\t\tfailures: row.failures,\n\t\t\t\t\tidempotentKeys: idempotentKeys\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlogger?.debug(`Queried queue with id ${this.id} with filter:`, filter, '-- found', entries.length, 'entries');\n\n\t\t\treturn(entries);\n\t\t}));\n\t}\n\n\tasync partition(path: string) : Promise<KeetaAnchorQueueStorageDriver<QueueRequest, QueueResult>> {\n\t\tthis.methodLogger('partition')?.debug(`Creating partitioned queue storage driver for path: ${path}`);\n\n\t\tif (this.dbInternal === null) {\n\t\t\tthrow(new Error('Asked to partition the instance, but the instance has been destroyed'));\n\t\t}\n\n\t\tconst retval = new KeetaAnchorQueueStorageDriverSQLite3<QueueRequest, QueueResult>({\n\t\t\tid: `${this.id}::${path}`,\n\t\t\tlogger: this.logger,\n\t\t\tdb: this.dbInternal,\n\t\t\tpath: [...this.path, path]\n\t\t});\n\n\t\treturn(retval);\n\t}\n\n\tasync destroy(): Promise<void> {\n\t\tthis.methodLogger('destroy')?.debug('Destroying instance');\n\n\t\tthis.dbInternal = null;\n\t}\n\n\tasync [Symbol.asyncDispose](): Promise<void> {\n\t\treturn(await this.destroy());\n\t}\n}\n"]}
|