@trigger.dev/redis-worker 4.3.2 → 4.4.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.
package/dist/index.d.cts CHANGED
@@ -449,6 +449,20 @@ interface ConcurrencyCheckResult {
449
449
  /** If not allowed, which group is blocking */
450
450
  blockedBy?: ConcurrencyState;
451
451
  }
452
+ /**
453
+ * Information about a reclaimed message from visibility timeout.
454
+ * Used to release concurrency after a message is returned to the queue.
455
+ */
456
+ interface ReclaimedMessageInfo {
457
+ /** Message ID */
458
+ messageId: string;
459
+ /** Queue ID */
460
+ queueId: string;
461
+ /** Tenant ID for concurrency release */
462
+ tenantId: string;
463
+ /** Additional metadata for concurrency group extraction */
464
+ metadata?: Record<string, unknown>;
465
+ }
452
466
  /**
453
467
  * Queues grouped by tenant for the scheduler.
454
468
  */
@@ -994,6 +1008,14 @@ declare class ConcurrencyManager {
994
1008
  * Release concurrency slots for a message across all groups.
995
1009
  */
996
1010
  release(queue: QueueDescriptor, messageId: string): Promise<void>;
1011
+ /**
1012
+ * Release concurrency slots for multiple messages in a single pipeline.
1013
+ * More efficient than calling release() multiple times.
1014
+ */
1015
+ releaseBatch(messages: Array<{
1016
+ queue: QueueDescriptor;
1017
+ messageId: string;
1018
+ }>): Promise<void>;
997
1019
  /**
998
1020
  * Get current concurrency for a specific group.
999
1021
  */
@@ -1151,13 +1173,13 @@ declare class VisibilityManager {
1151
1173
  *
1152
1174
  * @param shardId - The shard to check
1153
1175
  * @param getQueueKeys - Function to get queue keys for a queue ID
1154
- * @returns Number of messages reclaimed
1176
+ * @returns Array of reclaimed message info for concurrency release
1155
1177
  */
1156
1178
  reclaimTimedOut(shardId: number, getQueueKeys: (queueId: string) => {
1157
1179
  queueKey: string;
1158
1180
  queueItemsKey: string;
1159
1181
  masterQueueKey: string;
1160
- }): Promise<number>;
1182
+ }): Promise<ReclaimedMessageInfo[]>;
1161
1183
  /**
1162
1184
  * Get all in-flight messages for a shard.
1163
1185
  */
@@ -1923,4 +1945,4 @@ declare module "@internal/redis" {
1923
1945
  }
1924
1946
  }
1925
1947
 
1926
- export { type AnyMessageCatalog, type AnyQueueItem, BaseScheduler, BatchedSpanManager, type BatchedSpanManagerOptions, CallbackFairQueueKeyProducer, type ClaimResult, type ConcurrencyCheckResult, type ConcurrencyGroupConfig, ConcurrencyManager, type ConcurrencyManagerOptions, type ConcurrencyState, type ConsumerLoopState, type CooloffOptions, CronSchema, CustomRetry, DRRScheduler, type DRRSchedulerConfig, type DeadLetterMessage, DefaultFairQueueKeyProducer, type EnqueueBatchOptions, type EnqueueOptions, ExponentialBackoffRetry, FairQueue, FairQueueAttributes, type FairQueueKeyProducer, type FairQueueMetrics, type FairQueueOptions, FairQueueTelemetry, type FairScheduler, FixedDelayRetry, type GlobalRateLimiter, ImmediateRetry, type InFlightMessage, type JobHandler, type JobHandlerParams, LinearBackoffRetry, MasterQueue, type MasterQueueOptions, type MessageCatalogKey, type MessageCatalogSchema, type MessageCatalogValue, type MessageHandler, type MessageHandlerContext, MessagingAttributes, NoRetry, NoopScheduler, type QueueCooloffState, type QueueDescriptor, type QueueItem, type QueueMessage, type QueueWithScore, type RetryOptions, type RetryStrategy, RoundRobinScheduler, type SchedulerContext, SimpleQueue, type StoredMessage, type TelemetryOptions, type TenantQueues, VisibilityManager, type VisibilityManagerOptions, WeightedScheduler, type WeightedSchedulerBiases, type WeightedSchedulerConfig, Worker, type WorkerCatalog, type WorkerConcurrencyOptions, WorkerQueueManager, type WorkerQueueManagerOptions, type WorkerQueueOptions, createDefaultRetryStrategy, defaultRetryOptions, isAbortError, noopTelemetry };
1948
+ export { type AnyMessageCatalog, type AnyQueueItem, BaseScheduler, BatchedSpanManager, type BatchedSpanManagerOptions, CallbackFairQueueKeyProducer, type ClaimResult, type ConcurrencyCheckResult, type ConcurrencyGroupConfig, ConcurrencyManager, type ConcurrencyManagerOptions, type ConcurrencyState, type ConsumerLoopState, type CooloffOptions, CronSchema, CustomRetry, DRRScheduler, type DRRSchedulerConfig, type DeadLetterMessage, DefaultFairQueueKeyProducer, type EnqueueBatchOptions, type EnqueueOptions, ExponentialBackoffRetry, FairQueue, FairQueueAttributes, type FairQueueKeyProducer, type FairQueueMetrics, type FairQueueOptions, FairQueueTelemetry, type FairScheduler, FixedDelayRetry, type GlobalRateLimiter, ImmediateRetry, type InFlightMessage, type JobHandler, type JobHandlerParams, LinearBackoffRetry, MasterQueue, type MasterQueueOptions, type MessageCatalogKey, type MessageCatalogSchema, type MessageCatalogValue, type MessageHandler, type MessageHandlerContext, MessagingAttributes, NoRetry, NoopScheduler, type QueueCooloffState, type QueueDescriptor, type QueueItem, type QueueMessage, type QueueWithScore, type ReclaimedMessageInfo, type RetryOptions, type RetryStrategy, RoundRobinScheduler, type SchedulerContext, SimpleQueue, type StoredMessage, type TelemetryOptions, type TenantQueues, VisibilityManager, type VisibilityManagerOptions, WeightedScheduler, type WeightedSchedulerBiases, type WeightedSchedulerConfig, Worker, type WorkerCatalog, type WorkerConcurrencyOptions, WorkerQueueManager, type WorkerQueueManagerOptions, type WorkerQueueOptions, createDefaultRetryStrategy, defaultRetryOptions, isAbortError, noopTelemetry };
package/dist/index.d.ts CHANGED
@@ -449,6 +449,20 @@ interface ConcurrencyCheckResult {
449
449
  /** If not allowed, which group is blocking */
450
450
  blockedBy?: ConcurrencyState;
451
451
  }
452
+ /**
453
+ * Information about a reclaimed message from visibility timeout.
454
+ * Used to release concurrency after a message is returned to the queue.
455
+ */
456
+ interface ReclaimedMessageInfo {
457
+ /** Message ID */
458
+ messageId: string;
459
+ /** Queue ID */
460
+ queueId: string;
461
+ /** Tenant ID for concurrency release */
462
+ tenantId: string;
463
+ /** Additional metadata for concurrency group extraction */
464
+ metadata?: Record<string, unknown>;
465
+ }
452
466
  /**
453
467
  * Queues grouped by tenant for the scheduler.
454
468
  */
@@ -994,6 +1008,14 @@ declare class ConcurrencyManager {
994
1008
  * Release concurrency slots for a message across all groups.
995
1009
  */
996
1010
  release(queue: QueueDescriptor, messageId: string): Promise<void>;
1011
+ /**
1012
+ * Release concurrency slots for multiple messages in a single pipeline.
1013
+ * More efficient than calling release() multiple times.
1014
+ */
1015
+ releaseBatch(messages: Array<{
1016
+ queue: QueueDescriptor;
1017
+ messageId: string;
1018
+ }>): Promise<void>;
997
1019
  /**
998
1020
  * Get current concurrency for a specific group.
999
1021
  */
@@ -1151,13 +1173,13 @@ declare class VisibilityManager {
1151
1173
  *
1152
1174
  * @param shardId - The shard to check
1153
1175
  * @param getQueueKeys - Function to get queue keys for a queue ID
1154
- * @returns Number of messages reclaimed
1176
+ * @returns Array of reclaimed message info for concurrency release
1155
1177
  */
1156
1178
  reclaimTimedOut(shardId: number, getQueueKeys: (queueId: string) => {
1157
1179
  queueKey: string;
1158
1180
  queueItemsKey: string;
1159
1181
  masterQueueKey: string;
1160
- }): Promise<number>;
1182
+ }): Promise<ReclaimedMessageInfo[]>;
1161
1183
  /**
1162
1184
  * Get all in-flight messages for a shard.
1163
1185
  */
@@ -1923,4 +1945,4 @@ declare module "@internal/redis" {
1923
1945
  }
1924
1946
  }
1925
1947
 
1926
- export { type AnyMessageCatalog, type AnyQueueItem, BaseScheduler, BatchedSpanManager, type BatchedSpanManagerOptions, CallbackFairQueueKeyProducer, type ClaimResult, type ConcurrencyCheckResult, type ConcurrencyGroupConfig, ConcurrencyManager, type ConcurrencyManagerOptions, type ConcurrencyState, type ConsumerLoopState, type CooloffOptions, CronSchema, CustomRetry, DRRScheduler, type DRRSchedulerConfig, type DeadLetterMessage, DefaultFairQueueKeyProducer, type EnqueueBatchOptions, type EnqueueOptions, ExponentialBackoffRetry, FairQueue, FairQueueAttributes, type FairQueueKeyProducer, type FairQueueMetrics, type FairQueueOptions, FairQueueTelemetry, type FairScheduler, FixedDelayRetry, type GlobalRateLimiter, ImmediateRetry, type InFlightMessage, type JobHandler, type JobHandlerParams, LinearBackoffRetry, MasterQueue, type MasterQueueOptions, type MessageCatalogKey, type MessageCatalogSchema, type MessageCatalogValue, type MessageHandler, type MessageHandlerContext, MessagingAttributes, NoRetry, NoopScheduler, type QueueCooloffState, type QueueDescriptor, type QueueItem, type QueueMessage, type QueueWithScore, type RetryOptions, type RetryStrategy, RoundRobinScheduler, type SchedulerContext, SimpleQueue, type StoredMessage, type TelemetryOptions, type TenantQueues, VisibilityManager, type VisibilityManagerOptions, WeightedScheduler, type WeightedSchedulerBiases, type WeightedSchedulerConfig, Worker, type WorkerCatalog, type WorkerConcurrencyOptions, WorkerQueueManager, type WorkerQueueManagerOptions, type WorkerQueueOptions, createDefaultRetryStrategy, defaultRetryOptions, isAbortError, noopTelemetry };
1948
+ export { type AnyMessageCatalog, type AnyQueueItem, BaseScheduler, BatchedSpanManager, type BatchedSpanManagerOptions, CallbackFairQueueKeyProducer, type ClaimResult, type ConcurrencyCheckResult, type ConcurrencyGroupConfig, ConcurrencyManager, type ConcurrencyManagerOptions, type ConcurrencyState, type ConsumerLoopState, type CooloffOptions, CronSchema, CustomRetry, DRRScheduler, type DRRSchedulerConfig, type DeadLetterMessage, DefaultFairQueueKeyProducer, type EnqueueBatchOptions, type EnqueueOptions, ExponentialBackoffRetry, FairQueue, FairQueueAttributes, type FairQueueKeyProducer, type FairQueueMetrics, type FairQueueOptions, FairQueueTelemetry, type FairScheduler, FixedDelayRetry, type GlobalRateLimiter, ImmediateRetry, type InFlightMessage, type JobHandler, type JobHandlerParams, LinearBackoffRetry, MasterQueue, type MasterQueueOptions, type MessageCatalogKey, type MessageCatalogSchema, type MessageCatalogValue, type MessageHandler, type MessageHandlerContext, MessagingAttributes, NoRetry, NoopScheduler, type QueueCooloffState, type QueueDescriptor, type QueueItem, type QueueMessage, type QueueWithScore, type ReclaimedMessageInfo, type RetryOptions, type RetryStrategy, RoundRobinScheduler, type SchedulerContext, SimpleQueue, type StoredMessage, type TelemetryOptions, type TenantQueues, VisibilityManager, type VisibilityManagerOptions, WeightedScheduler, type WeightedSchedulerBiases, type WeightedSchedulerConfig, Worker, type WorkerCatalog, type WorkerConcurrencyOptions, WorkerQueueManager, type WorkerQueueManagerOptions, type WorkerQueueOptions, createDefaultRetryStrategy, defaultRetryOptions, isAbortError, noopTelemetry };
package/dist/index.js CHANGED
@@ -11800,6 +11800,24 @@ var ConcurrencyManager = class {
11800
11800
  }
11801
11801
  await pipeline.exec();
11802
11802
  }
11803
+ /**
11804
+ * Release concurrency slots for multiple messages in a single pipeline.
11805
+ * More efficient than calling release() multiple times.
11806
+ */
11807
+ async releaseBatch(messages) {
11808
+ if (messages.length === 0) {
11809
+ return;
11810
+ }
11811
+ const pipeline = this.redis.pipeline();
11812
+ for (const { queue, messageId } of messages) {
11813
+ for (const group of this.groups) {
11814
+ const groupId = group.extractGroupId(queue);
11815
+ const key = this.keys.concurrencyKey(group.name, groupId);
11816
+ pipeline.srem(key, messageId);
11817
+ }
11818
+ }
11819
+ await pipeline.exec();
11820
+ }
11803
11821
  /**
11804
11822
  * Get current concurrency for a specific group.
11805
11823
  */
@@ -12894,7 +12912,7 @@ var VisibilityManager = class {
12894
12912
  *
12895
12913
  * @param shardId - The shard to check
12896
12914
  * @param getQueueKeys - Function to get queue keys for a queue ID
12897
- * @returns Number of messages reclaimed
12915
+ * @returns Array of reclaimed message info for concurrency release
12898
12916
  */
12899
12917
  async reclaimTimedOut(shardId, getQueueKeys) {
12900
12918
  const inflightKey = this.keys.inflightKey(shardId);
@@ -12910,17 +12928,25 @@ var VisibilityManager = class {
12910
12928
  100
12911
12929
  // Process in batches
12912
12930
  );
12913
- let reclaimed = 0;
12931
+ const reclaimedMessages = [];
12914
12932
  for (let i = 0; i < timedOut.length; i += 2) {
12915
12933
  const member = timedOut[i];
12916
- const originalScore = timedOut[i + 1];
12917
- if (!member || !originalScore) {
12934
+ const _deadlineScore = timedOut[i + 1];
12935
+ if (!member || !_deadlineScore) {
12918
12936
  continue;
12919
12937
  }
12920
12938
  const { messageId, queueId } = this.#parseMember(member);
12921
12939
  const { queueKey, queueItemsKey, masterQueueKey } = getQueueKeys(queueId);
12922
12940
  try {
12923
- const score = parseFloat(originalScore) || now;
12941
+ const dataJson = await this.redis.hget(inflightDataKey, messageId);
12942
+ let storedMessage = null;
12943
+ if (dataJson) {
12944
+ try {
12945
+ storedMessage = JSON.parse(dataJson);
12946
+ } catch {
12947
+ }
12948
+ }
12949
+ const score = storedMessage?.timestamp ?? now;
12924
12950
  await this.redis.releaseMessage(
12925
12951
  inflightKey,
12926
12952
  inflightDataKey,
@@ -12932,11 +12958,29 @@ var VisibilityManager = class {
12932
12958
  score.toString(),
12933
12959
  queueId
12934
12960
  );
12935
- reclaimed++;
12961
+ if (storedMessage) {
12962
+ reclaimedMessages.push({
12963
+ messageId,
12964
+ queueId,
12965
+ tenantId: storedMessage.tenantId,
12966
+ metadata: storedMessage.metadata
12967
+ });
12968
+ } else {
12969
+ this.logger.error("Missing or corrupted message data during reclaim, using fallback", {
12970
+ messageId,
12971
+ queueId
12972
+ });
12973
+ reclaimedMessages.push({
12974
+ messageId,
12975
+ queueId,
12976
+ tenantId: this.keys.extractTenantId(queueId),
12977
+ metadata: {}
12978
+ });
12979
+ }
12936
12980
  this.logger.debug("Reclaimed timed-out message", {
12937
12981
  messageId,
12938
12982
  queueId,
12939
- originalScore
12983
+ deadline: _deadlineScore
12940
12984
  });
12941
12985
  } catch (error) {
12942
12986
  this.logger.error("Failed to reclaim message", {
@@ -12946,7 +12990,7 @@ var VisibilityManager = class {
12946
12990
  });
12947
12991
  }
12948
12992
  }
12949
- return reclaimed;
12993
+ return reclaimedMessages;
12950
12994
  }
12951
12995
  /**
12952
12996
  * Get all in-flight messages for a shard.
@@ -15349,12 +15393,31 @@ var FairQueue = class {
15349
15393
  async #reclaimTimedOutMessages() {
15350
15394
  let totalReclaimed = 0;
15351
15395
  for (let shardId = 0; shardId < this.shardCount; shardId++) {
15352
- const reclaimed = await this.visibilityManager.reclaimTimedOut(shardId, (queueId) => ({
15396
+ const reclaimedMessages = await this.visibilityManager.reclaimTimedOut(shardId, (queueId) => ({
15353
15397
  queueKey: this.keys.queueKey(queueId),
15354
15398
  queueItemsKey: this.keys.queueItemsKey(queueId),
15355
15399
  masterQueueKey: this.keys.masterQueueKey(this.masterQueue.getShardForQueue(queueId))
15356
15400
  }));
15357
- totalReclaimed += reclaimed;
15401
+ if (this.concurrencyManager && reclaimedMessages.length > 0) {
15402
+ try {
15403
+ await this.concurrencyManager.releaseBatch(
15404
+ reclaimedMessages.map((msg) => ({
15405
+ queue: {
15406
+ id: msg.queueId,
15407
+ tenantId: msg.tenantId,
15408
+ metadata: msg.metadata ?? {}
15409
+ },
15410
+ messageId: msg.messageId
15411
+ }))
15412
+ );
15413
+ } catch (error) {
15414
+ this.logger.error("Failed to release concurrency for reclaimed messages", {
15415
+ count: reclaimedMessages.length,
15416
+ error: error instanceof Error ? error.message : String(error)
15417
+ });
15418
+ }
15419
+ }
15420
+ totalReclaimed += reclaimedMessages.length;
15358
15421
  }
15359
15422
  if (totalReclaimed > 0) {
15360
15423
  this.logger.info("Reclaimed timed-out messages", { count: totalReclaimed });