@getstrata/core 2.2.14 → 2.2.15
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/CHANGELOG.md +35 -14
- package/dist/core/database/baseRepository.d.ts +1 -0
- package/dist/core/database/defaultConnection.d.ts +2 -1
- package/dist/core/database/relationQuery.d.ts +4 -0
- package/dist/core/queue/redisQueue.d.ts +5 -1
- package/dist/core/queue/redisStreams.d.ts +8 -2
- package/dist/entries/queue/createAppQueue.js +202 -92
- package/dist/entries/queue/publicQueue.js +202 -92
- package/dist/entries/queue/queueMetrics.js +202 -92
- package/dist/entries/queue/redisQueue.js +203 -92
- package/dist/framework/public-api.d.ts +1 -1
- package/dist/index.js +357 -143
- package/package.json +1 -1
|
@@ -380,21 +380,6 @@ redis.call('XDEL', KEYS[1], ARGV[2])
|
|
|
380
380
|
if #redis.call('XPENDING', KEYS[1], ARGV[1], '-', '+', 1, ARGV[3]) == 0 then redis.call('XGROUP', 'DELCONSUMER', KEYS[1], ARGV[1], ARGV[3]) end
|
|
381
381
|
return 1
|
|
382
382
|
`;
|
|
383
|
-
var PROMOTE_RETRIES = `
|
|
384
|
-
local kinds = {'stream','zset'}
|
|
385
|
-
for i=1,2 do
|
|
386
|
-
local kind = redis.call('TYPE', KEYS[i]).ok
|
|
387
|
-
if kind ~= 'none' and kind ~= kinds[i] then return redis.error_reply('Invalid stream retry promotion key type') end
|
|
388
|
-
end
|
|
389
|
-
local now = redis.call('TIME')
|
|
390
|
-
local due = tonumber(now[1])*1000 + math.floor(tonumber(now[2])/1000)
|
|
391
|
-
local entries = redis.call('ZRANGE', KEYS[2], '-inf', due, 'BYSCORE', 'LIMIT', 0, 100)
|
|
392
|
-
for _, payload in ipairs(entries) do
|
|
393
|
-
redis.call('XADD', KEYS[1], '*', 'payload', payload)
|
|
394
|
-
redis.call('ZREM', KEYS[2], payload)
|
|
395
|
-
end
|
|
396
|
-
return #entries
|
|
397
|
-
`;
|
|
398
383
|
async function scheduleStreamRetry(client, key, reservation, envelope, delayMs) {
|
|
399
384
|
if (!Number.isSafeInteger(delayMs) || delayMs < 0 || delayMs > Number.MAX_SAFE_INTEGER / 2)
|
|
400
385
|
throw new Error("Invalid Streams retry delay");
|
|
@@ -416,8 +401,93 @@ async function scheduleStreamRetry(client, key, reservation, envelope, delayMs)
|
|
|
416
401
|
if (Number(scheduled) !== 1)
|
|
417
402
|
throw new Error("Queue lease lost while scheduling retry");
|
|
418
403
|
}
|
|
419
|
-
|
|
420
|
-
|
|
404
|
+
var POLL_STREAM_PRIORITIES = `
|
|
405
|
+
local group = ARGV[1]
|
|
406
|
+
local owner = ARGV[2]
|
|
407
|
+
local visibility = ARGV[3]
|
|
408
|
+
local function payloadOf(fields)
|
|
409
|
+
for index = 1, #fields, 2 do
|
|
410
|
+
if fields[index] == 'payload' and type(fields[index + 1]) == 'string' then return fields[index + 1] end
|
|
411
|
+
end
|
|
412
|
+
return ''
|
|
413
|
+
end
|
|
414
|
+
local cursors = {}
|
|
415
|
+
for i = 1, #KEYS / 2 do cursors[i] = ARGV[3 + i] end
|
|
416
|
+
for i = 1, #KEYS / 2 do
|
|
417
|
+
local stream = KEYS[(i - 1) * 2 + 1]
|
|
418
|
+
local retries = KEYS[(i - 1) * 2 + 2]
|
|
419
|
+
local cursor = ARGV[3 + i]
|
|
420
|
+
local streamKind = redis.call('TYPE', stream).ok
|
|
421
|
+
local retryKind = redis.call('TYPE', retries).ok
|
|
422
|
+
if streamKind ~= 'none' and streamKind ~= 'stream' then return redis.error_reply('Invalid stream retry promotion key type') end
|
|
423
|
+
if retryKind ~= 'none' and retryKind ~= 'zset' then return redis.error_reply('Invalid stream retry promotion key type') end
|
|
424
|
+
if streamKind == 'stream' then
|
|
425
|
+
local now = redis.call('TIME')
|
|
426
|
+
local due = tonumber(now[1]) * 1000 + math.floor(tonumber(now[2]) / 1000)
|
|
427
|
+
local ready = redis.call('ZRANGE', retries, '-inf', due, 'BYSCORE', 'LIMIT', 0, 100)
|
|
428
|
+
for _, payload in ipairs(ready) do
|
|
429
|
+
redis.call('XADD', stream, '*', 'payload', payload)
|
|
430
|
+
redis.call('ZREM', retries, payload)
|
|
431
|
+
end
|
|
432
|
+
local window = redis.call('XPENDING', stream, group, cursor, '+', 10)
|
|
433
|
+
local claimed = redis.call('XAUTOCLAIM', stream, group, owner, visibility, cursor, 'COUNT', 1)
|
|
434
|
+
for _, entry in ipairs(window) do
|
|
435
|
+
if entry[2] ~= owner and #redis.call('XPENDING', stream, group, '-', '+', 1, entry[2]) == 0 then
|
|
436
|
+
redis.call('XGROUP', 'DELCONSUMER', stream, group, entry[2])
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
if #redis.call('XPENDING', stream, group, '-', '+', 1, owner) == 0 then
|
|
440
|
+
redis.call('XGROUP', 'DELCONSUMER', stream, group, owner)
|
|
441
|
+
end
|
|
442
|
+
cursors[i] = claimed[1]
|
|
443
|
+
if #claimed[2] > 0 then
|
|
444
|
+
return {'1', tostring(i), claimed[2][1][1], payloadOf(claimed[2][1][2]), unpack(cursors)}
|
|
445
|
+
end
|
|
446
|
+
local fresh = redis.call('XREADGROUP', 'GROUP', group, owner, 'COUNT', 1, 'STREAMS', stream, '>')
|
|
447
|
+
if not fresh and #redis.call('XPENDING', stream, group, '-', '+', 1, owner) == 0 then
|
|
448
|
+
redis.call('XGROUP', 'DELCONSUMER', stream, group, owner)
|
|
449
|
+
end
|
|
450
|
+
if fresh and #fresh > 0 and #fresh[1][2] > 0 then
|
|
451
|
+
return {'1', tostring(i), fresh[1][2][1][1], payloadOf(fresh[1][2][1][2]), unpack(cursors)}
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
return {'0', unpack(cursors)}
|
|
456
|
+
`;
|
|
457
|
+
async function pollStreamPriorities(client, queueKeys, owner, cursors) {
|
|
458
|
+
const keys = [];
|
|
459
|
+
for (const key of queueKeys)
|
|
460
|
+
keys.push(streamQueueKey(key), streamRetryKey(key));
|
|
461
|
+
const raw = await client.send("EVAL", [
|
|
462
|
+
POLL_STREAM_PRIORITIES,
|
|
463
|
+
String(keys.length),
|
|
464
|
+
...keys,
|
|
465
|
+
STREAM_GROUP,
|
|
466
|
+
owner,
|
|
467
|
+
String(readQueueVisibilityMs()),
|
|
468
|
+
...cursors
|
|
469
|
+
]);
|
|
470
|
+
if (!Array.isArray(raw))
|
|
471
|
+
throw new Error("Invalid Redis stream poll response");
|
|
472
|
+
const flag = String(raw[0]);
|
|
473
|
+
const cursorCount = queueKeys.length;
|
|
474
|
+
if (flag === "0") {
|
|
475
|
+
if (raw.length !== cursorCount + 1)
|
|
476
|
+
throw new Error("Invalid Redis stream poll response");
|
|
477
|
+
return { cursors: raw.slice(1).map(String), hit: null };
|
|
478
|
+
}
|
|
479
|
+
if (flag !== "1" || raw.length !== cursorCount + 4)
|
|
480
|
+
throw new Error("Invalid Redis stream poll response");
|
|
481
|
+
const index = Number(raw[1]);
|
|
482
|
+
if (!Number.isInteger(index) || index < 1 || index > queueKeys.length)
|
|
483
|
+
throw new Error("Invalid Redis stream poll response");
|
|
484
|
+
return {
|
|
485
|
+
cursors: raw.slice(4).map(String),
|
|
486
|
+
hit: {
|
|
487
|
+
index: index - 1,
|
|
488
|
+
reservation: { id: String(raw[2]), owner, payload: String(raw[3]) }
|
|
489
|
+
}
|
|
490
|
+
};
|
|
421
491
|
}
|
|
422
492
|
async function readStreamQueueDepth(client, key) {
|
|
423
493
|
return Number(await client.send("EVAL", [
|
|
@@ -466,20 +536,6 @@ end
|
|
|
466
536
|
if #redis.call('XPENDING', KEYS[1], ARGV[1], '-', '+', 1, ARGV[3]) == 0 then redis.call('XGROUP', 'DELCONSUMER', KEYS[1], ARGV[1], ARGV[3]) end
|
|
467
537
|
return acknowledged
|
|
468
538
|
`;
|
|
469
|
-
var CLAIM_STREAM = `
|
|
470
|
-
local window = redis.call('XPENDING', KEYS[1], ARGV[1], ARGV[4], '+', 10)
|
|
471
|
-
local claimed = redis.call('XAUTOCLAIM', KEYS[1], ARGV[1], ARGV[2], ARGV[3], ARGV[4], 'COUNT', 1)
|
|
472
|
-
for _, entry in ipairs(window) do
|
|
473
|
-
if entry[2] ~= ARGV[2] and #redis.call('XPENDING', KEYS[1], ARGV[1], '-', '+', 1, entry[2]) == 0 then redis.call('XGROUP', 'DELCONSUMER', KEYS[1], ARGV[1], entry[2]) end
|
|
474
|
-
end
|
|
475
|
-
if #redis.call('XPENDING', KEYS[1], ARGV[1], '-', '+', 1, ARGV[2]) == 0 then redis.call('XGROUP', 'DELCONSUMER', KEYS[1], ARGV[1], ARGV[2]) end
|
|
476
|
-
return claimed
|
|
477
|
-
`;
|
|
478
|
-
var READ_STREAM = `
|
|
479
|
-
local entries = redis.call('XREADGROUP', 'GROUP', ARGV[1], ARGV[2], 'COUNT', 1, 'STREAMS', KEYS[1], '>')
|
|
480
|
-
if not entries and #redis.call('XPENDING', KEYS[1], ARGV[1], '-', '+', 1, ARGV[2]) == 0 then redis.call('XGROUP', 'DELCONSUMER', KEYS[1], ARGV[1], ARGV[2]) end
|
|
481
|
-
return entries
|
|
482
|
-
`;
|
|
483
539
|
async function ensureStreamGroup(client, key) {
|
|
484
540
|
await assertLegacyDrained(client, key);
|
|
485
541
|
try {
|
|
@@ -489,17 +545,6 @@ async function ensureStreamGroup(client, key) {
|
|
|
489
545
|
throw error;
|
|
490
546
|
}
|
|
491
547
|
}
|
|
492
|
-
function readStreamEntry(value, owner) {
|
|
493
|
-
if (!Array.isArray(value) || typeof value[0] !== "string" || !Array.isArray(value[1]))
|
|
494
|
-
throw new Error("Invalid Redis stream entry response");
|
|
495
|
-
const fields = value[1];
|
|
496
|
-
let payload;
|
|
497
|
-
for (let index = 0;index < fields.length; index += 2) {
|
|
498
|
-
if (fields[index] === "payload" && typeof fields[index + 1] === "string")
|
|
499
|
-
payload = fields[index + 1];
|
|
500
|
-
}
|
|
501
|
-
return { id: value[0], owner, payload: payload ?? "" };
|
|
502
|
-
}
|
|
503
548
|
async function updateStreamReservation(client, key, reservation, action, controlKey) {
|
|
504
549
|
return Number(await client.send("EVAL", [
|
|
505
550
|
UPDATE_STREAM,
|
|
@@ -516,35 +561,6 @@ async function updateStreamReservation(client, key, reservation, action, control
|
|
|
516
561
|
controlKey ? "1" : "0"
|
|
517
562
|
])) === 1;
|
|
518
563
|
}
|
|
519
|
-
async function reserveStreamJob(client, key, owner, cursor = "0-0") {
|
|
520
|
-
const claimed = await client.send("EVAL", [
|
|
521
|
-
CLAIM_STREAM,
|
|
522
|
-
"1",
|
|
523
|
-
streamQueueKey(key),
|
|
524
|
-
STREAM_GROUP,
|
|
525
|
-
owner,
|
|
526
|
-
String(readQueueVisibilityMs()),
|
|
527
|
-
cursor
|
|
528
|
-
]);
|
|
529
|
-
if (!Array.isArray(claimed) || typeof claimed[0] !== "string" || !Array.isArray(claimed[1]))
|
|
530
|
-
throw new Error("Invalid Redis XAUTOCLAIM response");
|
|
531
|
-
const nextCursor = claimed[0];
|
|
532
|
-
if (claimed[1].length > 0)
|
|
533
|
-
return { reservation: readStreamEntry(claimed[1][0], owner), cursor: nextCursor };
|
|
534
|
-
const fresh = await client.send("EVAL", [
|
|
535
|
-
READ_STREAM,
|
|
536
|
-
"1",
|
|
537
|
-
streamQueueKey(key),
|
|
538
|
-
STREAM_GROUP,
|
|
539
|
-
owner
|
|
540
|
-
]);
|
|
541
|
-
if (fresh === null)
|
|
542
|
-
return { reservation: null, cursor: nextCursor };
|
|
543
|
-
if (!Array.isArray(fresh) || !Array.isArray(fresh[0]) || !Array.isArray(fresh[0][1]))
|
|
544
|
-
throw new Error("Invalid Redis XREADGROUP response");
|
|
545
|
-
return { reservation: readStreamEntry(fresh[0][1][0], owner), cursor: nextCursor };
|
|
546
|
-
}
|
|
547
|
-
|
|
548
564
|
class RedisStreamsQueue {
|
|
549
565
|
client;
|
|
550
566
|
constructor(redisUrl) {
|
|
@@ -642,12 +658,6 @@ class RedisStreamsWorker {
|
|
|
642
658
|
await ensureStreamGroup(this.client, key);
|
|
643
659
|
this.initialized = true;
|
|
644
660
|
}
|
|
645
|
-
async reserve(key) {
|
|
646
|
-
await promoteStreamRetries(this.client, key);
|
|
647
|
-
const result = await reserveStreamJob(this.client, key, this.owner, this.cursors.get(key));
|
|
648
|
-
this.cursors.set(key, result.cursor);
|
|
649
|
-
return result.reservation;
|
|
650
|
-
}
|
|
651
661
|
async processNext() {
|
|
652
662
|
if (this.processing)
|
|
653
663
|
throw new Error("Queue worker already processing a job.");
|
|
@@ -664,13 +674,19 @@ class RedisStreamsWorker {
|
|
|
664
674
|
await this.initialize();
|
|
665
675
|
const deadline = performance.now() + this.timeoutSeconds * 1000;
|
|
666
676
|
do {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
677
|
+
if (this.stopping)
|
|
678
|
+
return false;
|
|
679
|
+
const polled = await pollStreamPriorities(this.client, this.queueKeys, this.owner, this.queueKeys.map((key) => this.cursors.get(key) ?? "0-0"));
|
|
680
|
+
this.queueKeys.forEach((key, index) => {
|
|
681
|
+
const cursor = polled.cursors[index];
|
|
682
|
+
if (cursor)
|
|
683
|
+
this.cursors.set(key, cursor);
|
|
684
|
+
});
|
|
685
|
+
if (polled.hit) {
|
|
686
|
+
const key = this.queueKeys[polled.hit.index];
|
|
687
|
+
if (!key)
|
|
688
|
+
throw new Error("Invalid Redis stream poll response");
|
|
689
|
+
await this.handle(key, polled.hit.reservation);
|
|
674
690
|
return true;
|
|
675
691
|
}
|
|
676
692
|
if (performance.now() >= deadline || this.stopping)
|
|
@@ -943,6 +959,66 @@ for _, record in ipairs(redis.call('LRANGE', KEYS[2], 0, -1)) do
|
|
|
943
959
|
end
|
|
944
960
|
return reclaimed
|
|
945
961
|
`;
|
|
962
|
+
var POLL_LIST_PRIORITIES = `${SCRIPT_HEADER}
|
|
963
|
+
local owner = ARGV[1]
|
|
964
|
+
local visibility = ARGV[2]
|
|
965
|
+
local reservationId = ARGV[3]
|
|
966
|
+
local reclaim = ARGV[4] == '1'
|
|
967
|
+
local function reclaimQueue(listKey, processingKey, leaseKey)
|
|
968
|
+
local err = checkType(listKey, 'list') or checkType(processingKey, 'list') or checkType(leaseKey, 'hash')
|
|
969
|
+
if err then return err end
|
|
970
|
+
local now = nowMs()
|
|
971
|
+
for _, record in ipairs(redis.call('LRANGE', processingKey, 0, -1)) do
|
|
972
|
+
local payload, field = record, record
|
|
973
|
+
local modern = false
|
|
974
|
+
local ok, reservation = pcall(cjson.decode, record)
|
|
975
|
+
if ok and type(reservation) == 'table' and reservation.strataReservation == 1 then
|
|
976
|
+
payload, field, modern = reservation.payload, reservation.id, true
|
|
977
|
+
end
|
|
978
|
+
local raw = redis.call('HGET', leaseKey, field)
|
|
979
|
+
local expired = true
|
|
980
|
+
if raw then
|
|
981
|
+
if modern then
|
|
982
|
+
local leaseOk, lease = pcall(cjson.decode, raw)
|
|
983
|
+
expired = not leaseOk or type(lease) ~= 'table' or not tonumber(lease.expiresAt) or tonumber(lease.expiresAt) <= now
|
|
984
|
+
else
|
|
985
|
+
local reservedAt = tonumber(raw)
|
|
986
|
+
expired = not reservedAt or now - reservedAt >= tonumber(visibility)
|
|
987
|
+
end
|
|
988
|
+
end
|
|
989
|
+
if expired then
|
|
990
|
+
redis.call('LPUSH', listKey, payload)
|
|
991
|
+
redis.call('LREM', processingKey, 1, record)
|
|
992
|
+
redis.call('HDEL', leaseKey, field)
|
|
993
|
+
end
|
|
994
|
+
end
|
|
995
|
+
end
|
|
996
|
+
local function reserveQueue(listKey, processingKey, leaseKey)
|
|
997
|
+
local err = checkType(listKey, 'list') or checkType(processingKey, 'list') or checkType(leaseKey, 'hash')
|
|
998
|
+
if err then return err end
|
|
999
|
+
local payload = redis.call('LINDEX', listKey, -1)
|
|
1000
|
+
if not payload then return nil end
|
|
1001
|
+
local record = cjson.encode({strataReservation=1, id=reservationId, owner=owner, payload=payload})
|
|
1002
|
+
local lease = cjson.encode({owner=owner, expiresAt=nowMs()+tonumber(visibility)})
|
|
1003
|
+
redis.call('LPUSH', processingKey, record)
|
|
1004
|
+
redis.call('HSET', leaseKey, reservationId, lease)
|
|
1005
|
+
redis.call('RPOP', listKey)
|
|
1006
|
+
return record
|
|
1007
|
+
end
|
|
1008
|
+
local count = #KEYS / 3
|
|
1009
|
+
if reclaim then
|
|
1010
|
+
for i = 1, count do
|
|
1011
|
+
local err = reclaimQueue(KEYS[(i - 1) * 3 + 1], KEYS[(i - 1) * 3 + 2], KEYS[(i - 1) * 3 + 3])
|
|
1012
|
+
if err then return err end
|
|
1013
|
+
end
|
|
1014
|
+
end
|
|
1015
|
+
for i = 1, count do
|
|
1016
|
+
local record = reserveQueue(KEYS[(i - 1) * 3 + 1], KEYS[(i - 1) * 3 + 2], KEYS[(i - 1) * 3 + 3])
|
|
1017
|
+
if type(record) == 'string' then return {'1', tostring(i), record} end
|
|
1018
|
+
if record then return record end
|
|
1019
|
+
end
|
|
1020
|
+
return {'0'}
|
|
1021
|
+
`;
|
|
946
1022
|
function queueInvalidKey(queueKey) {
|
|
947
1023
|
return `${queueKey}:invalid`;
|
|
948
1024
|
}
|
|
@@ -977,6 +1053,41 @@ async function updateQueueReservation(client, queueKey, reservation, action) {
|
|
|
977
1053
|
reservation.payload
|
|
978
1054
|
])) === 1;
|
|
979
1055
|
}
|
|
1056
|
+
async function pollListPriorities(client, queueKeys, owner, reservationId, reclaim) {
|
|
1057
|
+
const keys = [];
|
|
1058
|
+
for (const key of queueKeys) {
|
|
1059
|
+
keys.push(key, queueProcessingKey(key), queueProcessingLeaseKey(key));
|
|
1060
|
+
}
|
|
1061
|
+
const raw = await client.send("EVAL", [
|
|
1062
|
+
POLL_LIST_PRIORITIES,
|
|
1063
|
+
String(keys.length),
|
|
1064
|
+
...keys,
|
|
1065
|
+
owner,
|
|
1066
|
+
String(readQueueVisibilityMs()),
|
|
1067
|
+
reservationId,
|
|
1068
|
+
reclaim ? "1" : "0"
|
|
1069
|
+
]);
|
|
1070
|
+
if (!Array.isArray(raw))
|
|
1071
|
+
throw new Error("Invalid Redis list poll response");
|
|
1072
|
+
const flag = String(raw[0]);
|
|
1073
|
+
if (flag === "0") {
|
|
1074
|
+
if (raw.length !== 1)
|
|
1075
|
+
throw new Error("Invalid Redis list poll response");
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
if (flag !== "1" || raw.length !== 3)
|
|
1079
|
+
throw new Error("Invalid Redis list poll response");
|
|
1080
|
+
const index = Number(raw[1]);
|
|
1081
|
+
const record = raw[2];
|
|
1082
|
+
if (!Number.isInteger(index) || index < 1 || index > queueKeys.length || typeof record !== "string") {
|
|
1083
|
+
throw new Error("Invalid Redis list poll response");
|
|
1084
|
+
}
|
|
1085
|
+
const queueKey = queueKeys[index - 1];
|
|
1086
|
+
if (!queueKey)
|
|
1087
|
+
throw new Error("Invalid Redis list poll response");
|
|
1088
|
+
const reservation = JSON.parse(record);
|
|
1089
|
+
return { queueKey, reservation: { ...reservation, record } };
|
|
1090
|
+
}
|
|
980
1091
|
async function reclaimExpiredQueueReservations(client, queueKeys = QUEUE_KEYS) {
|
|
981
1092
|
let reclaimed = 0;
|
|
982
1093
|
for (const key of queueKeys) {
|
|
@@ -1037,14 +1148,14 @@ class QueueWorker {
|
|
|
1037
1148
|
}
|
|
1038
1149
|
async reserve() {
|
|
1039
1150
|
const deadline = performance.now() + this.timeoutSeconds * 1000;
|
|
1151
|
+
let reclaim = true;
|
|
1040
1152
|
do {
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
}
|
|
1153
|
+
if (this.stopping)
|
|
1154
|
+
return null;
|
|
1155
|
+
const reserved = await pollListPriorities(this.client, this.queueKeys, this.owner, crypto.randomUUID(), reclaim);
|
|
1156
|
+
reclaim = false;
|
|
1157
|
+
if (reserved)
|
|
1158
|
+
return reserved;
|
|
1048
1159
|
if (this.stopping || performance.now() >= deadline)
|
|
1049
1160
|
return null;
|
|
1050
1161
|
await Bun.sleep(Math.min(100, Math.max(1, deadline - performance.now())));
|
|
@@ -1054,7 +1165,6 @@ class QueueWorker {
|
|
|
1054
1165
|
async processNext() {
|
|
1055
1166
|
if (this.stopping)
|
|
1056
1167
|
return false;
|
|
1057
|
-
await reclaimExpiredQueueReservations(this.client, this.queueKeys);
|
|
1058
1168
|
const reserved = await this.reserve();
|
|
1059
1169
|
if (!reserved)
|
|
1060
1170
|
return false;
|
|
@@ -1139,6 +1249,7 @@ export {
|
|
|
1139
1249
|
countPendingQueueJobs,
|
|
1140
1250
|
migrateLegacyQueueToStreams,
|
|
1141
1251
|
parseQueueJobEnvelope,
|
|
1252
|
+
pollListPriorities,
|
|
1142
1253
|
queueInvalidKey,
|
|
1143
1254
|
queueKeyForPriority,
|
|
1144
1255
|
queueProcessingKey,
|
|
@@ -42,7 +42,7 @@ export { bindDatabaseConnection, getBoundDatabaseConnection, resetBoundDatabaseC
|
|
|
42
42
|
export { bindBunSql, createBunSqlPool } from "../core/database/bunSql.ts";
|
|
43
43
|
export { createDatabaseConnection } from "../core/database/connection.ts";
|
|
44
44
|
export { getActiveDatabaseConnection, hasActiveDatabaseConnection, runWithDatabaseConnection, } from "../core/database/connectionContext.ts";
|
|
45
|
-
export { getDefaultDatabasePool, getDefaultDatabaseQuery, registerDefaultDatabasePool, resetDefaultDatabasePoolForTests, } from "../core/database/defaultConnection.ts";
|
|
45
|
+
export { getDefaultDatabasePool, getDefaultDatabaseQuery, isDefaultDatabaseConnection, registerDefaultDatabasePool, resetDefaultDatabasePoolForTests, } from "../core/database/defaultConnection.ts";
|
|
46
46
|
export type { SqlDialect } from "../core/database/dialect.ts";
|
|
47
47
|
export { currentSqlDialect, dialectFor, resetSqlDialect, runWithSqlDialect, sqlTimestamp, useSqlDialect, } from "../core/database/dialect.ts";
|
|
48
48
|
export { mapDatabaseError, withDatabaseErrorHandling } from "../core/database/errors.ts";
|