@trigger.dev/redis-worker 0.0.0-prerelease-20251209163704 → 0.0.0-prerelease-20251211173228
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +96 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -2
- package/dist/index.d.ts +28 -2
- package/dist/index.js +96 -23
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -11784,12 +11784,7 @@ var ConcurrencyManager = class {
|
|
|
11784
11784
|
);
|
|
11785
11785
|
const keys = groupData.map((g) => g.key);
|
|
11786
11786
|
const limits = groupData.map((g) => g.limit.toString());
|
|
11787
|
-
const result = await this.redis.reserveConcurrency(
|
|
11788
|
-
keys.length.toString(),
|
|
11789
|
-
messageId,
|
|
11790
|
-
...keys,
|
|
11791
|
-
...limits
|
|
11792
|
-
);
|
|
11787
|
+
const result = await this.redis.reserveConcurrency(keys.length, keys, messageId, ...limits);
|
|
11793
11788
|
return result === 1;
|
|
11794
11789
|
}
|
|
11795
11790
|
/**
|
|
@@ -11885,16 +11880,14 @@ var ConcurrencyManager = class {
|
|
|
11885
11880
|
// ============================================================================
|
|
11886
11881
|
#registerCommands() {
|
|
11887
11882
|
this.redis.defineCommand("reserveConcurrency", {
|
|
11888
|
-
numberOfKeys: 0,
|
|
11889
|
-
// Will pass number of keys in ARGV
|
|
11890
11883
|
lua: `
|
|
11891
|
-
local numGroups =
|
|
11892
|
-
local messageId = ARGV[
|
|
11884
|
+
local numGroups = #KEYS
|
|
11885
|
+
local messageId = ARGV[1]
|
|
11893
11886
|
|
|
11894
11887
|
-- Check all groups first
|
|
11895
11888
|
for i = 1, numGroups do
|
|
11896
|
-
local key =
|
|
11897
|
-
local limit = tonumber(ARGV[
|
|
11889
|
+
local key = KEYS[i]
|
|
11890
|
+
local limit = tonumber(ARGV[1 + i]) -- Limits start at ARGV[2]
|
|
11898
11891
|
local current = redis.call('SCARD', key)
|
|
11899
11892
|
|
|
11900
11893
|
if current >= limit then
|
|
@@ -11904,7 +11897,7 @@ end
|
|
|
11904
11897
|
|
|
11905
11898
|
-- All groups have capacity, add message to all
|
|
11906
11899
|
for i = 1, numGroups do
|
|
11907
|
-
local key =
|
|
11900
|
+
local key = KEYS[i]
|
|
11908
11901
|
redis.call('SADD', key, messageId)
|
|
11909
11902
|
end
|
|
11910
11903
|
|
|
@@ -13222,7 +13215,20 @@ var DRRScheduler = class extends BaseScheduler {
|
|
|
13222
13215
|
const eligibleTenants = tenantData.filter(
|
|
13223
13216
|
(t) => !t.isAtCapacity && t.deficit >= 1
|
|
13224
13217
|
);
|
|
13218
|
+
const blockedTenants = tenantData.filter((t) => t.isAtCapacity);
|
|
13219
|
+
if (blockedTenants.length > 0) {
|
|
13220
|
+
this.logger.debug("DRR: tenants blocked by concurrency", {
|
|
13221
|
+
blockedCount: blockedTenants.length,
|
|
13222
|
+
blockedTenants: blockedTenants.map((t) => t.tenantId)
|
|
13223
|
+
});
|
|
13224
|
+
}
|
|
13225
13225
|
eligibleTenants.sort((a, b) => b.deficit - a.deficit);
|
|
13226
|
+
this.logger.debug("DRR: queue selection complete", {
|
|
13227
|
+
totalQueues: queues.length,
|
|
13228
|
+
totalTenants: tenantIds.length,
|
|
13229
|
+
eligibleTenants: eligibleTenants.length,
|
|
13230
|
+
topTenantDeficit: eligibleTenants[0]?.deficit
|
|
13231
|
+
});
|
|
13226
13232
|
return eligibleTenants.map((t) => ({
|
|
13227
13233
|
tenantId: t.tenantId,
|
|
13228
13234
|
queues: t.queues
|
|
@@ -13878,6 +13884,7 @@ var FairQueue = class {
|
|
|
13878
13884
|
this.cooloffEnabled = options.cooloff?.enabled ?? true;
|
|
13879
13885
|
this.cooloffThreshold = options.cooloff?.threshold ?? 10;
|
|
13880
13886
|
this.cooloffPeriodMs = options.cooloff?.periodMs ?? 1e4;
|
|
13887
|
+
this.globalRateLimiter = options.globalRateLimiter;
|
|
13881
13888
|
this.telemetry = new FairQueueTelemetry({
|
|
13882
13889
|
tracer: options.tracer,
|
|
13883
13890
|
meter: options.meter,
|
|
@@ -13948,6 +13955,8 @@ var FairQueue = class {
|
|
|
13948
13955
|
cooloffThreshold;
|
|
13949
13956
|
cooloffPeriodMs;
|
|
13950
13957
|
queueCooloffStates = /* @__PURE__ */ new Map();
|
|
13958
|
+
// Global rate limiter
|
|
13959
|
+
globalRateLimiter;
|
|
13951
13960
|
// Runtime state
|
|
13952
13961
|
messageHandler;
|
|
13953
13962
|
isRunning = false;
|
|
@@ -13958,6 +13967,30 @@ var FairQueue = class {
|
|
|
13958
13967
|
// Queue descriptor cache for message processing
|
|
13959
13968
|
queueDescriptorCache = /* @__PURE__ */ new Map();
|
|
13960
13969
|
// ============================================================================
|
|
13970
|
+
// Public API - Telemetry
|
|
13971
|
+
// ============================================================================
|
|
13972
|
+
/**
|
|
13973
|
+
* Register observable gauge callbacks for telemetry.
|
|
13974
|
+
* Call this after FairQueue is created to enable gauge metrics.
|
|
13975
|
+
*
|
|
13976
|
+
* @param options.observedTenants - List of tenant IDs to observe for DLQ metrics
|
|
13977
|
+
*/
|
|
13978
|
+
registerTelemetryGauges(options) {
|
|
13979
|
+
this.telemetry.registerGaugeCallbacks({
|
|
13980
|
+
getMasterQueueLength: async (shardId) => {
|
|
13981
|
+
return await this.masterQueue.getShardQueueCount(shardId);
|
|
13982
|
+
},
|
|
13983
|
+
getInflightCount: async (shardId) => {
|
|
13984
|
+
return await this.visibilityManager.getInflightCount(shardId);
|
|
13985
|
+
},
|
|
13986
|
+
getDLQLength: async (tenantId) => {
|
|
13987
|
+
return await this.getDeadLetterQueueLength(tenantId);
|
|
13988
|
+
},
|
|
13989
|
+
shardCount: this.shardCount,
|
|
13990
|
+
observedTenants: options?.observedTenants
|
|
13991
|
+
});
|
|
13992
|
+
}
|
|
13993
|
+
// ============================================================================
|
|
13961
13994
|
// Public API - Message Handler
|
|
13962
13995
|
// ============================================================================
|
|
13963
13996
|
/**
|
|
@@ -14409,6 +14442,16 @@ var FairQueue = class {
|
|
|
14409
14442
|
return false;
|
|
14410
14443
|
}
|
|
14411
14444
|
}
|
|
14445
|
+
if (this.globalRateLimiter) {
|
|
14446
|
+
const result = await this.globalRateLimiter.limit();
|
|
14447
|
+
if (!result.allowed && result.resetAt) {
|
|
14448
|
+
const waitMs = Math.max(0, result.resetAt - Date.now());
|
|
14449
|
+
if (waitMs > 0) {
|
|
14450
|
+
this.logger.debug("Global rate limit reached, waiting", { waitMs, loopId });
|
|
14451
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
14452
|
+
}
|
|
14453
|
+
}
|
|
14454
|
+
}
|
|
14412
14455
|
const claimResult = await this.visibilityManager.claim(
|
|
14413
14456
|
queueId,
|
|
14414
14457
|
queueKey,
|
|
@@ -14534,18 +14577,33 @@ var FairQueue = class {
|
|
|
14534
14577
|
return;
|
|
14535
14578
|
}
|
|
14536
14579
|
for (const { tenantId, queues } of tenantQueues) {
|
|
14537
|
-
|
|
14538
|
-
|
|
14539
|
-
|
|
14580
|
+
let availableSlots = 1;
|
|
14581
|
+
if (this.concurrencyManager) {
|
|
14582
|
+
const [current, limit] = await Promise.all([
|
|
14583
|
+
this.concurrencyManager.getCurrentConcurrency("tenant", tenantId),
|
|
14584
|
+
this.concurrencyManager.getConcurrencyLimit("tenant", tenantId)
|
|
14585
|
+
]);
|
|
14586
|
+
availableSlots = Math.max(1, limit - current);
|
|
14587
|
+
}
|
|
14588
|
+
let slotsUsed = 0;
|
|
14589
|
+
queueLoop: for (const queueId of queues) {
|
|
14590
|
+
while (slotsUsed < availableSlots) {
|
|
14591
|
+
if (this.cooloffEnabled && this.#isInCooloff(queueId)) {
|
|
14592
|
+
break;
|
|
14593
|
+
}
|
|
14594
|
+
const processed = await this.#processOneMessage(loopId, queueId, tenantId, shardId);
|
|
14595
|
+
if (processed) {
|
|
14596
|
+
await this.scheduler.recordProcessed?.(tenantId, queueId);
|
|
14597
|
+
this.#resetCooloff(queueId);
|
|
14598
|
+
slotsUsed++;
|
|
14599
|
+
} else {
|
|
14600
|
+
this.#incrementCooloff(queueId);
|
|
14601
|
+
break;
|
|
14602
|
+
}
|
|
14540
14603
|
}
|
|
14541
|
-
|
|
14542
|
-
|
|
14543
|
-
await this.scheduler.recordProcessed?.(tenantId, queueId);
|
|
14544
|
-
this.#resetCooloff(queueId);
|
|
14545
|
-
} else {
|
|
14546
|
-
this.#incrementCooloff(queueId);
|
|
14604
|
+
if (slotsUsed >= availableSlots) {
|
|
14605
|
+
break queueLoop;
|
|
14547
14606
|
}
|
|
14548
|
-
break;
|
|
14549
14607
|
}
|
|
14550
14608
|
}
|
|
14551
14609
|
}
|
|
@@ -14564,6 +14622,16 @@ var FairQueue = class {
|
|
|
14564
14622
|
return false;
|
|
14565
14623
|
}
|
|
14566
14624
|
}
|
|
14625
|
+
if (this.globalRateLimiter) {
|
|
14626
|
+
const result = await this.globalRateLimiter.limit();
|
|
14627
|
+
if (!result.allowed && result.resetAt) {
|
|
14628
|
+
const waitMs = Math.max(0, result.resetAt - Date.now());
|
|
14629
|
+
if (waitMs > 0) {
|
|
14630
|
+
this.logger.debug("Global rate limit reached, waiting", { waitMs, loopId });
|
|
14631
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
14632
|
+
}
|
|
14633
|
+
}
|
|
14634
|
+
}
|
|
14567
14635
|
const claimResult = await this.visibilityManager.claim(
|
|
14568
14636
|
queueId,
|
|
14569
14637
|
queueKey,
|
|
@@ -14888,6 +14956,11 @@ var FairQueue = class {
|
|
|
14888
14956
|
tag: "cooloff",
|
|
14889
14957
|
expiresAt: Date.now() + this.cooloffPeriodMs
|
|
14890
14958
|
});
|
|
14959
|
+
this.logger.debug("Queue entered cooloff", {
|
|
14960
|
+
queueId,
|
|
14961
|
+
cooloffPeriodMs: this.cooloffPeriodMs,
|
|
14962
|
+
consecutiveFailures: newFailures
|
|
14963
|
+
});
|
|
14891
14964
|
} else {
|
|
14892
14965
|
this.queueCooloffStates.set(queueId, {
|
|
14893
14966
|
tag: "normal",
|