@trigger.dev/redis-worker 4.5.0-rc.7 → 4.5.1
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 +368 -337
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +460 -443
- package/dist/index.d.ts +460 -443
- package/dist/index.js +368 -337
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -64,6 +64,22 @@ declare class SimpleQueue<TMessageCatalog extends MessageCatalogSchema> {
|
|
|
64
64
|
size({ includeFuture }?: {
|
|
65
65
|
includeFuture?: boolean;
|
|
66
66
|
}): Promise<number>;
|
|
67
|
+
/**
|
|
68
|
+
* Age (in ms) of the oldest *overdue* message — the oldest item whose scheduled
|
|
69
|
+
* time has already passed (score <= now). Returns 0 when the queue is empty or
|
|
70
|
+
* only holds future/delayed or in-flight (future-scored) items.
|
|
71
|
+
*
|
|
72
|
+
* Resolves the candidate against the `items` hash so orphaned `queue` entries
|
|
73
|
+
* (a member whose payload is missing — the same stale state `dequeueItems`
|
|
74
|
+
* cleans up) don't report a phantom stall for work that can't be dequeued. The
|
|
75
|
+
* Lua scans due items oldest-first and returns the first score whose payload
|
|
76
|
+
* still exists.
|
|
77
|
+
*
|
|
78
|
+
* This is the generic stall signal: it stays at 0 while a queue drains healthily
|
|
79
|
+
* and rises only when due work sits undrained (poison block, dead consumer,
|
|
80
|
+
* backpressure).
|
|
81
|
+
*/
|
|
82
|
+
oldestMessageAge(): Promise<number>;
|
|
67
83
|
getJob(id: string): Promise<QueueItem<TMessageCatalog> | null>;
|
|
68
84
|
moveToDeadLetterQueue(id: string, errorMessage: string): Promise<void>;
|
|
69
85
|
sizeOfDeadLetterQueue(): Promise<number>;
|
|
@@ -80,6 +96,7 @@ declare module "@internal/redis" {
|
|
|
80
96
|
moveToDeadLetterQueue(queue: string, items: string, dlq: string, dlqItems: string, id: string, errorMessage: string, callback?: Callback<number>): Result<number, Context>;
|
|
81
97
|
enqueueItemOnce(queue: string, items: string, id: string, score: number, serializedItem: string, callback?: Callback<number>): Result<number, Context>;
|
|
82
98
|
getJob(queue: string, items: string, id: string, callback?: Callback<[string, string, string] | null>): Result<[string, string, string] | null, Context>;
|
|
99
|
+
getOldestDueScore(queue: string, items: string, now: number, callback?: Callback<string | number>): Result<string | number, Context>;
|
|
83
100
|
}
|
|
84
101
|
}
|
|
85
102
|
|
|
@@ -893,6 +910,101 @@ interface WeightedSchedulerConfig {
|
|
|
893
910
|
tracer?: Tracer;
|
|
894
911
|
}
|
|
895
912
|
|
|
913
|
+
interface ConcurrencyManagerOptions {
|
|
914
|
+
redis: RedisOptions;
|
|
915
|
+
keys: FairQueueKeyProducer;
|
|
916
|
+
groups: ConcurrencyGroupConfig[];
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* ConcurrencyManager handles multi-level concurrency tracking and limiting.
|
|
920
|
+
*
|
|
921
|
+
* Features:
|
|
922
|
+
* - Multiple concurrent concurrency groups (tenant, org, project, etc.)
|
|
923
|
+
* - Atomic reserve/release operations using Lua scripts
|
|
924
|
+
* - Efficient batch checking of all groups
|
|
925
|
+
*/
|
|
926
|
+
declare class ConcurrencyManager {
|
|
927
|
+
#private;
|
|
928
|
+
private options;
|
|
929
|
+
private redis;
|
|
930
|
+
private keys;
|
|
931
|
+
private groups;
|
|
932
|
+
private groupsByName;
|
|
933
|
+
constructor(options: ConcurrencyManagerOptions);
|
|
934
|
+
/**
|
|
935
|
+
* Check if a message can be processed given all concurrency constraints.
|
|
936
|
+
* Checks all configured groups and returns the first one at capacity.
|
|
937
|
+
*/
|
|
938
|
+
canProcess(queue: QueueDescriptor): Promise<ConcurrencyCheckResult>;
|
|
939
|
+
/**
|
|
940
|
+
* Reserve concurrency slots for a message across all groups.
|
|
941
|
+
* Atomic - either all groups are reserved or none.
|
|
942
|
+
*
|
|
943
|
+
* @returns true if reservation successful, false if any group is at capacity
|
|
944
|
+
*/
|
|
945
|
+
reserve(queue: QueueDescriptor, messageId: string): Promise<boolean>;
|
|
946
|
+
/**
|
|
947
|
+
* Release concurrency slots for a message across all groups.
|
|
948
|
+
*/
|
|
949
|
+
release(queue: QueueDescriptor, messageId: string): Promise<void>;
|
|
950
|
+
/**
|
|
951
|
+
* Release concurrency slots for multiple messages in a single pipeline.
|
|
952
|
+
* More efficient than calling release() multiple times.
|
|
953
|
+
*/
|
|
954
|
+
releaseBatch(messages: Array<{
|
|
955
|
+
queue: QueueDescriptor;
|
|
956
|
+
messageId: string;
|
|
957
|
+
}>): Promise<void>;
|
|
958
|
+
/**
|
|
959
|
+
* Get current concurrency for a specific group.
|
|
960
|
+
*/
|
|
961
|
+
getCurrentConcurrency(groupName: string, groupId: string): Promise<number>;
|
|
962
|
+
/**
|
|
963
|
+
* Get available capacity for a queue across all concurrency groups.
|
|
964
|
+
* Returns the minimum available capacity across all groups.
|
|
965
|
+
*/
|
|
966
|
+
getAvailableCapacity(queue: QueueDescriptor): Promise<number>;
|
|
967
|
+
/**
|
|
968
|
+
* Get concurrency limit for a specific group.
|
|
969
|
+
*/
|
|
970
|
+
getConcurrencyLimit(groupName: string, groupId: string): Promise<number>;
|
|
971
|
+
/**
|
|
972
|
+
* Check if a group is at capacity.
|
|
973
|
+
*/
|
|
974
|
+
isAtCapacity(groupName: string, groupId: string): Promise<boolean>;
|
|
975
|
+
/**
|
|
976
|
+
* Get full state for a group.
|
|
977
|
+
*/
|
|
978
|
+
getState(groupName: string, groupId: string): Promise<ConcurrencyState>;
|
|
979
|
+
/**
|
|
980
|
+
* Get all active message IDs for a group.
|
|
981
|
+
*/
|
|
982
|
+
getActiveMessages(groupName: string, groupId: string): Promise<string[]>;
|
|
983
|
+
/**
|
|
984
|
+
* Force-clear concurrency for a group (use with caution).
|
|
985
|
+
* Useful for cleanup after crashes.
|
|
986
|
+
*/
|
|
987
|
+
clearGroup(groupName: string, groupId: string): Promise<void>;
|
|
988
|
+
/**
|
|
989
|
+
* Remove a specific message from concurrency tracking.
|
|
990
|
+
* Useful for cleanup.
|
|
991
|
+
*/
|
|
992
|
+
removeMessage(messageId: string, queue: QueueDescriptor): Promise<void>;
|
|
993
|
+
/**
|
|
994
|
+
* Get configured group names.
|
|
995
|
+
*/
|
|
996
|
+
getGroupNames(): string[];
|
|
997
|
+
/**
|
|
998
|
+
* Close the Redis connection.
|
|
999
|
+
*/
|
|
1000
|
+
close(): Promise<void>;
|
|
1001
|
+
}
|
|
1002
|
+
declare module "@internal/redis" {
|
|
1003
|
+
interface RedisCommander<Context> {
|
|
1004
|
+
reserveConcurrency(numKeys: number, keys: string[], messageId: string, ...limits: string[]): Promise<number>;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
896
1008
|
/**
|
|
897
1009
|
* Default key producer for the fair queue system.
|
|
898
1010
|
* Uses a configurable prefix and standard key structure.
|
|
@@ -1051,479 +1163,132 @@ declare module "@internal/redis" {
|
|
|
1051
1163
|
}
|
|
1052
1164
|
}
|
|
1053
1165
|
|
|
1054
|
-
interface ConcurrencyManagerOptions {
|
|
1055
|
-
redis: RedisOptions;
|
|
1056
|
-
keys: FairQueueKeyProducer;
|
|
1057
|
-
groups: ConcurrencyGroupConfig[];
|
|
1058
|
-
}
|
|
1059
1166
|
/**
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
* Features:
|
|
1063
|
-
* - Multiple concurrent concurrency groups (tenant, org, project, etc.)
|
|
1064
|
-
* - Atomic reserve/release operations using Lua scripts
|
|
1065
|
-
* - Efficient batch checking of all groups
|
|
1167
|
+
* Base class for scheduler implementations.
|
|
1168
|
+
* Provides common utilities and default implementations.
|
|
1066
1169
|
*/
|
|
1067
|
-
declare class
|
|
1068
|
-
#private;
|
|
1069
|
-
private options;
|
|
1070
|
-
private redis;
|
|
1071
|
-
private keys;
|
|
1072
|
-
private groups;
|
|
1073
|
-
private groupsByName;
|
|
1074
|
-
constructor(options: ConcurrencyManagerOptions);
|
|
1170
|
+
declare abstract class BaseScheduler implements FairScheduler {
|
|
1075
1171
|
/**
|
|
1076
|
-
*
|
|
1077
|
-
*
|
|
1172
|
+
* Select queues for processing from a master queue shard.
|
|
1173
|
+
* Must be implemented by subclasses.
|
|
1078
1174
|
*/
|
|
1079
|
-
|
|
1175
|
+
abstract selectQueues(masterQueueShard: string, consumerId: string, context: SchedulerContext): Promise<TenantQueues[]>;
|
|
1080
1176
|
/**
|
|
1081
|
-
*
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1084
|
-
* @returns true if reservation successful, false if any group is at capacity
|
|
1177
|
+
* Called after processing a message to update scheduler state.
|
|
1178
|
+
* Default implementation does nothing.
|
|
1085
1179
|
*/
|
|
1086
|
-
|
|
1180
|
+
recordProcessed(_tenantId: string, _queueId: string): Promise<void>;
|
|
1087
1181
|
/**
|
|
1088
|
-
*
|
|
1182
|
+
* Called after processing multiple messages to update scheduler state.
|
|
1183
|
+
* Batch variant for efficiency - reduces Redis calls when processing multiple messages.
|
|
1184
|
+
* Default implementation does nothing.
|
|
1089
1185
|
*/
|
|
1090
|
-
|
|
1186
|
+
recordProcessedBatch(_tenantId: string, _queueId: string, _count: number): Promise<void>;
|
|
1091
1187
|
/**
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1188
|
+
* Initialize the scheduler.
|
|
1189
|
+
* Default implementation does nothing.
|
|
1094
1190
|
*/
|
|
1095
|
-
|
|
1096
|
-
queue: QueueDescriptor;
|
|
1097
|
-
messageId: string;
|
|
1098
|
-
}>): Promise<void>;
|
|
1191
|
+
initialize(): Promise<void>;
|
|
1099
1192
|
/**
|
|
1100
|
-
*
|
|
1193
|
+
* Cleanup scheduler resources.
|
|
1194
|
+
* Default implementation does nothing.
|
|
1101
1195
|
*/
|
|
1102
|
-
|
|
1196
|
+
close(): Promise<void>;
|
|
1103
1197
|
/**
|
|
1104
|
-
*
|
|
1105
|
-
* Returns the minimum available capacity across all groups.
|
|
1198
|
+
* Helper to group queues by tenant.
|
|
1106
1199
|
*/
|
|
1107
|
-
|
|
1200
|
+
protected groupQueuesByTenant(queues: Array<{
|
|
1201
|
+
queueId: string;
|
|
1202
|
+
tenantId: string;
|
|
1203
|
+
}>): Map<string, string[]>;
|
|
1108
1204
|
/**
|
|
1109
|
-
*
|
|
1205
|
+
* Helper to convert grouped queues to TenantQueues array.
|
|
1110
1206
|
*/
|
|
1111
|
-
|
|
1207
|
+
protected toTenantQueuesArray(grouped: Map<string, string[]>): TenantQueues[];
|
|
1112
1208
|
/**
|
|
1113
|
-
*
|
|
1209
|
+
* Helper to filter out tenants at capacity.
|
|
1114
1210
|
*/
|
|
1115
|
-
|
|
1211
|
+
protected filterAtCapacity(tenants: TenantQueues[], context: SchedulerContext, groupName?: string): Promise<TenantQueues[]>;
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Simple noop scheduler that returns empty results.
|
|
1215
|
+
* Useful for testing or disabling scheduling.
|
|
1216
|
+
*/
|
|
1217
|
+
declare class NoopScheduler extends BaseScheduler {
|
|
1218
|
+
selectQueues(_masterQueueShard: string, _consumerId: string, _context: SchedulerContext): Promise<TenantQueues[]>;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
/**
|
|
1222
|
+
* Deficit Round Robin (DRR) Scheduler.
|
|
1223
|
+
*
|
|
1224
|
+
* DRR ensures fair processing across tenants by:
|
|
1225
|
+
* - Allocating a "quantum" of credits to each tenant per round
|
|
1226
|
+
* - Accumulating unused credits as "deficit"
|
|
1227
|
+
* - Processing from tenants with available deficit
|
|
1228
|
+
* - Capping deficit to prevent starvation
|
|
1229
|
+
*
|
|
1230
|
+
* Key improvements over basic implementations:
|
|
1231
|
+
* - Atomic deficit operations using Lua scripts
|
|
1232
|
+
* - Efficient iteration through tenants
|
|
1233
|
+
* - Automatic deficit cleanup for inactive tenants
|
|
1234
|
+
*/
|
|
1235
|
+
declare class DRRScheduler extends BaseScheduler {
|
|
1236
|
+
#private;
|
|
1237
|
+
private config;
|
|
1238
|
+
private redis;
|
|
1239
|
+
private keys;
|
|
1240
|
+
private quantum;
|
|
1241
|
+
private maxDeficit;
|
|
1242
|
+
private masterQueueLimit;
|
|
1243
|
+
private logger;
|
|
1244
|
+
constructor(config: DRRSchedulerConfig);
|
|
1116
1245
|
/**
|
|
1117
|
-
*
|
|
1246
|
+
* Select queues for processing using DRR algorithm.
|
|
1247
|
+
*
|
|
1248
|
+
* Algorithm:
|
|
1249
|
+
* 1. Get all queues from the master shard
|
|
1250
|
+
* 2. Group by tenant
|
|
1251
|
+
* 3. Filter out tenants at concurrency capacity
|
|
1252
|
+
* 4. Add quantum to each tenant's deficit (atomically)
|
|
1253
|
+
* 5. Select queues from tenants with deficit >= 1
|
|
1254
|
+
* 6. Order tenants by deficit (highest first for fairness)
|
|
1118
1255
|
*/
|
|
1119
|
-
|
|
1256
|
+
selectQueues(masterQueueShard: string, consumerId: string, context: SchedulerContext): Promise<TenantQueues[]>;
|
|
1120
1257
|
/**
|
|
1121
|
-
*
|
|
1258
|
+
* Select queues using the two-level tenant dispatch index.
|
|
1259
|
+
*
|
|
1260
|
+
* Algorithm:
|
|
1261
|
+
* 1. ZRANGEBYSCORE on dispatch index (gets only tenants with queues - much smaller)
|
|
1262
|
+
* 2. Add quantum to each tenant's deficit (atomically)
|
|
1263
|
+
* 3. Check capacity as safety net (dispatch should only have tenants with capacity)
|
|
1264
|
+
* 4. Select tenants with deficit >= 1, sorted by deficit (highest first)
|
|
1265
|
+
* 5. For each tenant, fetch their queues from Level 2 index
|
|
1122
1266
|
*/
|
|
1123
|
-
|
|
1267
|
+
selectQueuesFromDispatch(dispatchShardKey: string, consumerId: string, context: DispatchSchedulerContext): Promise<TenantQueues[]>;
|
|
1124
1268
|
/**
|
|
1125
|
-
*
|
|
1126
|
-
*
|
|
1269
|
+
* Record that a message was processed from a tenant.
|
|
1270
|
+
* Decrements the tenant's deficit.
|
|
1127
1271
|
*/
|
|
1128
|
-
|
|
1272
|
+
recordProcessed(tenantId: string, _queueId: string): Promise<void>;
|
|
1129
1273
|
/**
|
|
1130
|
-
*
|
|
1131
|
-
*
|
|
1274
|
+
* Record that multiple messages were processed from a tenant.
|
|
1275
|
+
* Decrements the tenant's deficit by count atomically.
|
|
1132
1276
|
*/
|
|
1133
|
-
|
|
1277
|
+
recordProcessedBatch(tenantId: string, _queueId: string, count: number): Promise<void>;
|
|
1278
|
+
close(): Promise<void>;
|
|
1134
1279
|
/**
|
|
1135
|
-
* Get
|
|
1280
|
+
* Get the current deficit for a tenant.
|
|
1136
1281
|
*/
|
|
1137
|
-
|
|
1282
|
+
getDeficit(tenantId: string): Promise<number>;
|
|
1138
1283
|
/**
|
|
1139
|
-
*
|
|
1284
|
+
* Reset deficit for a tenant.
|
|
1285
|
+
* Used when a tenant has no more active queues.
|
|
1140
1286
|
*/
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
interface VisibilityManagerOptions {
|
|
1150
|
-
redis: RedisOptions;
|
|
1151
|
-
keys: FairQueueKeyProducer;
|
|
1152
|
-
shardCount: number;
|
|
1153
|
-
defaultTimeoutMs: number;
|
|
1154
|
-
logger?: {
|
|
1155
|
-
debug: (message: string, context?: Record<string, unknown>) => void;
|
|
1156
|
-
error: (message: string, context?: Record<string, unknown>) => void;
|
|
1157
|
-
};
|
|
1158
|
-
}
|
|
1159
|
-
/**
|
|
1160
|
-
* VisibilityManager handles message visibility timeouts for safe message processing.
|
|
1161
|
-
*
|
|
1162
|
-
* Features:
|
|
1163
|
-
* - Claim messages with visibility timeout
|
|
1164
|
-
* - Heartbeat to extend timeout
|
|
1165
|
-
* - Automatic reclaim of timed-out messages
|
|
1166
|
-
* - Per-shard in-flight tracking
|
|
1167
|
-
*
|
|
1168
|
-
* Data structures:
|
|
1169
|
-
* - In-flight sorted set: score = deadline timestamp, member = "{messageId}:{queueId}"
|
|
1170
|
-
* - In-flight data hash: field = messageId, value = JSON message data
|
|
1171
|
-
*/
|
|
1172
|
-
declare class VisibilityManager {
|
|
1173
|
-
#private;
|
|
1174
|
-
private options;
|
|
1175
|
-
private redis;
|
|
1176
|
-
private keys;
|
|
1177
|
-
private shardCount;
|
|
1178
|
-
private defaultTimeoutMs;
|
|
1179
|
-
private logger;
|
|
1180
|
-
constructor(options: VisibilityManagerOptions);
|
|
1181
|
-
/**
|
|
1182
|
-
* Claim a message for processing.
|
|
1183
|
-
* Moves the message from its queue to the in-flight set with a visibility timeout.
|
|
1184
|
-
*
|
|
1185
|
-
* @param queueId - The queue to claim from
|
|
1186
|
-
* @param queueKey - The Redis key for the queue sorted set
|
|
1187
|
-
* @param queueItemsKey - The Redis key for the queue items hash
|
|
1188
|
-
* @param consumerId - ID of the consumer claiming the message
|
|
1189
|
-
* @param timeoutMs - Visibility timeout in milliseconds
|
|
1190
|
-
* @returns Claim result with the message if successful
|
|
1191
|
-
*/
|
|
1192
|
-
claim<TPayload = unknown>(queueId: string, queueKey: string, queueItemsKey: string, consumerId: string, timeoutMs?: number): Promise<ClaimResult<TPayload>>;
|
|
1193
|
-
/**
|
|
1194
|
-
* Claim multiple messages for processing (batch claim).
|
|
1195
|
-
* Moves up to maxCount messages from the queue to the in-flight set.
|
|
1196
|
-
*
|
|
1197
|
-
* @param queueId - The queue to claim from
|
|
1198
|
-
* @param queueKey - The Redis key for the queue sorted set
|
|
1199
|
-
* @param queueItemsKey - The Redis key for the queue items hash
|
|
1200
|
-
* @param consumerId - ID of the consumer claiming the messages
|
|
1201
|
-
* @param maxCount - Maximum number of messages to claim
|
|
1202
|
-
* @param timeoutMs - Visibility timeout in milliseconds
|
|
1203
|
-
* @returns Array of claimed messages
|
|
1204
|
-
*/
|
|
1205
|
-
claimBatch<TPayload = unknown>(queueId: string, queueKey: string, queueItemsKey: string, consumerId: string, maxCount: number, timeoutMs?: number): Promise<Array<InFlightMessage<TPayload>>>;
|
|
1206
|
-
/**
|
|
1207
|
-
* Extend the visibility timeout for a message (heartbeat).
|
|
1208
|
-
*
|
|
1209
|
-
* @param messageId - The message ID
|
|
1210
|
-
* @param queueId - The queue ID
|
|
1211
|
-
* @param extendMs - Additional milliseconds to add to the deadline
|
|
1212
|
-
* @returns true if the heartbeat was successful
|
|
1213
|
-
*/
|
|
1214
|
-
heartbeat(messageId: string, queueId: string, extendMs: number): Promise<boolean>;
|
|
1215
|
-
/**
|
|
1216
|
-
* Mark a message as successfully processed.
|
|
1217
|
-
* Removes the message from in-flight tracking.
|
|
1218
|
-
*
|
|
1219
|
-
* @param messageId - The message ID
|
|
1220
|
-
* @param queueId - The queue ID
|
|
1221
|
-
*/
|
|
1222
|
-
complete(messageId: string, queueId: string): Promise<void>;
|
|
1223
|
-
/**
|
|
1224
|
-
* Release a message back to its queue.
|
|
1225
|
-
* Used when processing fails or consumer wants to retry later.
|
|
1226
|
-
*
|
|
1227
|
-
* @param messageId - The message ID
|
|
1228
|
-
* @param queueId - The queue ID
|
|
1229
|
-
* @param queueKey - The Redis key for the queue
|
|
1230
|
-
* @param queueItemsKey - The Redis key for the queue items hash
|
|
1231
|
-
* @param tenantQueueIndexKey - The Redis key for the tenant queue index (Level 2)
|
|
1232
|
-
* @param dispatchKey - The Redis key for the dispatch index (Level 1)
|
|
1233
|
-
* @param tenantId - The tenant ID
|
|
1234
|
-
* @param score - Optional score for the message (defaults to now)
|
|
1235
|
-
*/
|
|
1236
|
-
release<TPayload = unknown>(messageId: string, queueId: string, queueKey: string, queueItemsKey: string, tenantQueueIndexKey: string, dispatchKey: string, tenantId: string, score?: number, updatedData?: string): Promise<void>;
|
|
1237
|
-
/**
|
|
1238
|
-
* Release multiple messages back to their queue in a single operation.
|
|
1239
|
-
* Used when processing fails or consumer wants to retry later.
|
|
1240
|
-
* All messages must belong to the same queue.
|
|
1241
|
-
*
|
|
1242
|
-
* @param messages - Array of messages to release (must all have same queueId)
|
|
1243
|
-
* @param queueId - The queue ID
|
|
1244
|
-
* @param queueKey - The Redis key for the queue
|
|
1245
|
-
* @param queueItemsKey - The Redis key for the queue items hash
|
|
1246
|
-
* @param tenantQueueIndexKey - The Redis key for the tenant queue index (Level 2)
|
|
1247
|
-
* @param dispatchKey - The Redis key for the dispatch index (Level 1)
|
|
1248
|
-
* @param tenantId - The tenant ID
|
|
1249
|
-
* @param score - Optional score for the messages (defaults to now)
|
|
1250
|
-
*/
|
|
1251
|
-
releaseBatch(messages: Array<{
|
|
1252
|
-
messageId: string;
|
|
1253
|
-
}>, queueId: string, queueKey: string, queueItemsKey: string, tenantQueueIndexKey: string, dispatchKey: string, tenantId: string, score?: number): Promise<void>;
|
|
1254
|
-
/**
|
|
1255
|
-
* Reclaim timed-out messages from a shard.
|
|
1256
|
-
* Returns messages to their original queues.
|
|
1257
|
-
*
|
|
1258
|
-
* @param shardId - The shard to check
|
|
1259
|
-
* @param getQueueKeys - Function to get queue keys for a queue ID
|
|
1260
|
-
* @returns Array of reclaimed message info for concurrency release
|
|
1261
|
-
*/
|
|
1262
|
-
reclaimTimedOut(shardId: number, getQueueKeys: (queueId: string) => {
|
|
1263
|
-
queueKey: string;
|
|
1264
|
-
queueItemsKey: string;
|
|
1265
|
-
tenantQueueIndexKey: string;
|
|
1266
|
-
dispatchKey: string;
|
|
1267
|
-
tenantId: string;
|
|
1268
|
-
}): Promise<ReclaimedMessageInfo[]>;
|
|
1269
|
-
/**
|
|
1270
|
-
* Get all in-flight messages for a shard.
|
|
1271
|
-
*/
|
|
1272
|
-
getInflightMessages(shardId: number): Promise<Array<{
|
|
1273
|
-
messageId: string;
|
|
1274
|
-
queueId: string;
|
|
1275
|
-
deadline: number;
|
|
1276
|
-
}>>;
|
|
1277
|
-
/**
|
|
1278
|
-
* Get count of in-flight messages for a shard.
|
|
1279
|
-
*/
|
|
1280
|
-
getInflightCount(shardId: number): Promise<number>;
|
|
1281
|
-
/**
|
|
1282
|
-
* Get total in-flight count across all shards.
|
|
1283
|
-
*/
|
|
1284
|
-
getTotalInflightCount(): Promise<number>;
|
|
1285
|
-
/**
|
|
1286
|
-
* Close the Redis connection.
|
|
1287
|
-
*/
|
|
1288
|
-
close(): Promise<void>;
|
|
1289
|
-
}
|
|
1290
|
-
declare module "@internal/redis" {
|
|
1291
|
-
interface RedisCommander<Context> {
|
|
1292
|
-
claimMessage(queueKey: string, queueItemsKey: string, inflightKey: string, inflightDataKey: string, queueId: string, consumerId: string, deadline: string): Promise<[string, string] | null>;
|
|
1293
|
-
claimMessageBatch(queueKey: string, queueItemsKey: string, inflightKey: string, inflightDataKey: string, queueId: string, deadline: string, maxCount: string): Promise<string[]>;
|
|
1294
|
-
releaseMessage(inflightKey: string, inflightDataKey: string, queueKey: string, queueItemsKey: string, tenantQueueIndexKey: string, dispatchKey: string, member: string, messageId: string, score: string, queueId: string, updatedData: string, tenantId: string): Promise<number>;
|
|
1295
|
-
releaseMessageBatch(inflightKey: string, inflightDataKey: string, queueKey: string, queueItemsKey: string, tenantQueueIndexKey: string, dispatchKey: string, score: string, queueId: string, tenantId: string, ...membersAndMessageIds: string[]): Promise<number>;
|
|
1296
|
-
heartbeatMessage(inflightKey: string, member: string, newDeadline: string): Promise<number>;
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
interface WorkerQueueManagerOptions {
|
|
1301
|
-
redis: RedisOptions;
|
|
1302
|
-
keys: FairQueueKeyProducer;
|
|
1303
|
-
logger?: {
|
|
1304
|
-
debug: (message: string, context?: Record<string, unknown>) => void;
|
|
1305
|
-
error: (message: string, context?: Record<string, unknown>) => void;
|
|
1306
|
-
};
|
|
1307
|
-
}
|
|
1308
|
-
/**
|
|
1309
|
-
* WorkerQueueManager handles the intermediate worker queue layer.
|
|
1310
|
-
*
|
|
1311
|
-
* This provides:
|
|
1312
|
-
* - Low-latency message delivery via blocking pop (BLPOP)
|
|
1313
|
-
* - Routing of messages to specific workers/consumers
|
|
1314
|
-
* - Efficient waiting without polling
|
|
1315
|
-
*
|
|
1316
|
-
* Flow:
|
|
1317
|
-
* 1. Master queue consumer claims message from message queue
|
|
1318
|
-
* 2. Message key is pushed to worker queue
|
|
1319
|
-
* 3. Worker queue consumer does blocking pop to receive message
|
|
1320
|
-
*/
|
|
1321
|
-
declare class WorkerQueueManager {
|
|
1322
|
-
#private;
|
|
1323
|
-
private options;
|
|
1324
|
-
private redis;
|
|
1325
|
-
private keys;
|
|
1326
|
-
private logger;
|
|
1327
|
-
constructor(options: WorkerQueueManagerOptions);
|
|
1328
|
-
/**
|
|
1329
|
-
* Push a message key to a worker queue.
|
|
1330
|
-
* Called after claiming a message from the message queue.
|
|
1331
|
-
*
|
|
1332
|
-
* @param workerQueueId - The worker queue identifier
|
|
1333
|
-
* @param messageKey - The message key to push (typically "messageId:queueId")
|
|
1334
|
-
*/
|
|
1335
|
-
push(workerQueueId: string, messageKey: string): Promise<void>;
|
|
1336
|
-
/**
|
|
1337
|
-
* Push multiple message keys to a worker queue.
|
|
1338
|
-
*
|
|
1339
|
-
* @param workerQueueId - The worker queue identifier
|
|
1340
|
-
* @param messageKeys - The message keys to push
|
|
1341
|
-
*/
|
|
1342
|
-
pushBatch(workerQueueId: string, messageKeys: string[]): Promise<void>;
|
|
1343
|
-
/**
|
|
1344
|
-
* Blocking pop from a worker queue.
|
|
1345
|
-
* Waits until a message is available or timeout expires.
|
|
1346
|
-
*
|
|
1347
|
-
* @param workerQueueId - The worker queue identifier
|
|
1348
|
-
* @param timeoutSeconds - Maximum time to wait (0 = wait forever)
|
|
1349
|
-
* @param signal - Optional abort signal to cancel waiting
|
|
1350
|
-
* @returns The message key, or null if timeout
|
|
1351
|
-
*/
|
|
1352
|
-
blockingPop(workerQueueId: string, timeoutSeconds: number, signal?: AbortSignal): Promise<string | null>;
|
|
1353
|
-
/**
|
|
1354
|
-
* Non-blocking pop from a worker queue.
|
|
1355
|
-
*
|
|
1356
|
-
* @param workerQueueId - The worker queue identifier
|
|
1357
|
-
* @returns The message key and queue length, or null if empty
|
|
1358
|
-
*/
|
|
1359
|
-
pop(workerQueueId: string): Promise<{
|
|
1360
|
-
messageKey: string;
|
|
1361
|
-
queueLength: number;
|
|
1362
|
-
} | null>;
|
|
1363
|
-
/**
|
|
1364
|
-
* Get the current length of a worker queue.
|
|
1365
|
-
*/
|
|
1366
|
-
getLength(workerQueueId: string): Promise<number>;
|
|
1367
|
-
/**
|
|
1368
|
-
* Peek at all messages in a worker queue without removing them.
|
|
1369
|
-
* Useful for debugging and tests.
|
|
1370
|
-
*/
|
|
1371
|
-
peek(workerQueueId: string): Promise<string[]>;
|
|
1372
|
-
/**
|
|
1373
|
-
* Remove a specific message from the worker queue.
|
|
1374
|
-
* Used when a message needs to be removed without processing.
|
|
1375
|
-
*
|
|
1376
|
-
* @param workerQueueId - The worker queue identifier
|
|
1377
|
-
* @param messageKey - The message key to remove
|
|
1378
|
-
* @returns Number of removed items
|
|
1379
|
-
*/
|
|
1380
|
-
remove(workerQueueId: string, messageKey: string): Promise<number>;
|
|
1381
|
-
/**
|
|
1382
|
-
* Clear all messages from a worker queue.
|
|
1383
|
-
*/
|
|
1384
|
-
clear(workerQueueId: string): Promise<void>;
|
|
1385
|
-
/**
|
|
1386
|
-
* Close the Redis connection.
|
|
1387
|
-
*/
|
|
1388
|
-
close(): Promise<void>;
|
|
1389
|
-
/**
|
|
1390
|
-
* Register custom commands on an external Redis client.
|
|
1391
|
-
* Use this when initializing FairQueue with worker queues.
|
|
1392
|
-
*/
|
|
1393
|
-
registerCommands(redis: Redis): void;
|
|
1394
|
-
}
|
|
1395
|
-
declare module "@internal/redis" {
|
|
1396
|
-
interface RedisCommander<Context> {
|
|
1397
|
-
popWithLength(workerQueueKey: string): Promise<[string, string] | null>;
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
|
|
1401
|
-
/**
|
|
1402
|
-
* Base class for scheduler implementations.
|
|
1403
|
-
* Provides common utilities and default implementations.
|
|
1404
|
-
*/
|
|
1405
|
-
declare abstract class BaseScheduler implements FairScheduler {
|
|
1406
|
-
/**
|
|
1407
|
-
* Select queues for processing from a master queue shard.
|
|
1408
|
-
* Must be implemented by subclasses.
|
|
1409
|
-
*/
|
|
1410
|
-
abstract selectQueues(masterQueueShard: string, consumerId: string, context: SchedulerContext): Promise<TenantQueues[]>;
|
|
1411
|
-
/**
|
|
1412
|
-
* Called after processing a message to update scheduler state.
|
|
1413
|
-
* Default implementation does nothing.
|
|
1414
|
-
*/
|
|
1415
|
-
recordProcessed(_tenantId: string, _queueId: string): Promise<void>;
|
|
1416
|
-
/**
|
|
1417
|
-
* Called after processing multiple messages to update scheduler state.
|
|
1418
|
-
* Batch variant for efficiency - reduces Redis calls when processing multiple messages.
|
|
1419
|
-
* Default implementation does nothing.
|
|
1420
|
-
*/
|
|
1421
|
-
recordProcessedBatch(_tenantId: string, _queueId: string, _count: number): Promise<void>;
|
|
1422
|
-
/**
|
|
1423
|
-
* Initialize the scheduler.
|
|
1424
|
-
* Default implementation does nothing.
|
|
1425
|
-
*/
|
|
1426
|
-
initialize(): Promise<void>;
|
|
1427
|
-
/**
|
|
1428
|
-
* Cleanup scheduler resources.
|
|
1429
|
-
* Default implementation does nothing.
|
|
1430
|
-
*/
|
|
1431
|
-
close(): Promise<void>;
|
|
1432
|
-
/**
|
|
1433
|
-
* Helper to group queues by tenant.
|
|
1434
|
-
*/
|
|
1435
|
-
protected groupQueuesByTenant(queues: Array<{
|
|
1436
|
-
queueId: string;
|
|
1437
|
-
tenantId: string;
|
|
1438
|
-
}>): Map<string, string[]>;
|
|
1439
|
-
/**
|
|
1440
|
-
* Helper to convert grouped queues to TenantQueues array.
|
|
1441
|
-
*/
|
|
1442
|
-
protected toTenantQueuesArray(grouped: Map<string, string[]>): TenantQueues[];
|
|
1443
|
-
/**
|
|
1444
|
-
* Helper to filter out tenants at capacity.
|
|
1445
|
-
*/
|
|
1446
|
-
protected filterAtCapacity(tenants: TenantQueues[], context: SchedulerContext, groupName?: string): Promise<TenantQueues[]>;
|
|
1447
|
-
}
|
|
1448
|
-
/**
|
|
1449
|
-
* Simple noop scheduler that returns empty results.
|
|
1450
|
-
* Useful for testing or disabling scheduling.
|
|
1451
|
-
*/
|
|
1452
|
-
declare class NoopScheduler extends BaseScheduler {
|
|
1453
|
-
selectQueues(_masterQueueShard: string, _consumerId: string, _context: SchedulerContext): Promise<TenantQueues[]>;
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
|
-
/**
|
|
1457
|
-
* Deficit Round Robin (DRR) Scheduler.
|
|
1458
|
-
*
|
|
1459
|
-
* DRR ensures fair processing across tenants by:
|
|
1460
|
-
* - Allocating a "quantum" of credits to each tenant per round
|
|
1461
|
-
* - Accumulating unused credits as "deficit"
|
|
1462
|
-
* - Processing from tenants with available deficit
|
|
1463
|
-
* - Capping deficit to prevent starvation
|
|
1464
|
-
*
|
|
1465
|
-
* Key improvements over basic implementations:
|
|
1466
|
-
* - Atomic deficit operations using Lua scripts
|
|
1467
|
-
* - Efficient iteration through tenants
|
|
1468
|
-
* - Automatic deficit cleanup for inactive tenants
|
|
1469
|
-
*/
|
|
1470
|
-
declare class DRRScheduler extends BaseScheduler {
|
|
1471
|
-
#private;
|
|
1472
|
-
private config;
|
|
1473
|
-
private redis;
|
|
1474
|
-
private keys;
|
|
1475
|
-
private quantum;
|
|
1476
|
-
private maxDeficit;
|
|
1477
|
-
private masterQueueLimit;
|
|
1478
|
-
private logger;
|
|
1479
|
-
constructor(config: DRRSchedulerConfig);
|
|
1480
|
-
/**
|
|
1481
|
-
* Select queues for processing using DRR algorithm.
|
|
1482
|
-
*
|
|
1483
|
-
* Algorithm:
|
|
1484
|
-
* 1. Get all queues from the master shard
|
|
1485
|
-
* 2. Group by tenant
|
|
1486
|
-
* 3. Filter out tenants at concurrency capacity
|
|
1487
|
-
* 4. Add quantum to each tenant's deficit (atomically)
|
|
1488
|
-
* 5. Select queues from tenants with deficit >= 1
|
|
1489
|
-
* 6. Order tenants by deficit (highest first for fairness)
|
|
1490
|
-
*/
|
|
1491
|
-
selectQueues(masterQueueShard: string, consumerId: string, context: SchedulerContext): Promise<TenantQueues[]>;
|
|
1492
|
-
/**
|
|
1493
|
-
* Select queues using the two-level tenant dispatch index.
|
|
1494
|
-
*
|
|
1495
|
-
* Algorithm:
|
|
1496
|
-
* 1. ZRANGEBYSCORE on dispatch index (gets only tenants with queues - much smaller)
|
|
1497
|
-
* 2. Add quantum to each tenant's deficit (atomically)
|
|
1498
|
-
* 3. Check capacity as safety net (dispatch should only have tenants with capacity)
|
|
1499
|
-
* 4. Select tenants with deficit >= 1, sorted by deficit (highest first)
|
|
1500
|
-
* 5. For each tenant, fetch their queues from Level 2 index
|
|
1501
|
-
*/
|
|
1502
|
-
selectQueuesFromDispatch(dispatchShardKey: string, consumerId: string, context: DispatchSchedulerContext): Promise<TenantQueues[]>;
|
|
1503
|
-
/**
|
|
1504
|
-
* Record that a message was processed from a tenant.
|
|
1505
|
-
* Decrements the tenant's deficit.
|
|
1506
|
-
*/
|
|
1507
|
-
recordProcessed(tenantId: string, _queueId: string): Promise<void>;
|
|
1508
|
-
/**
|
|
1509
|
-
* Record that multiple messages were processed from a tenant.
|
|
1510
|
-
* Decrements the tenant's deficit by count atomically.
|
|
1511
|
-
*/
|
|
1512
|
-
recordProcessedBatch(tenantId: string, _queueId: string, count: number): Promise<void>;
|
|
1513
|
-
close(): Promise<void>;
|
|
1514
|
-
/**
|
|
1515
|
-
* Get the current deficit for a tenant.
|
|
1516
|
-
*/
|
|
1517
|
-
getDeficit(tenantId: string): Promise<number>;
|
|
1518
|
-
/**
|
|
1519
|
-
* Reset deficit for a tenant.
|
|
1520
|
-
* Used when a tenant has no more active queues.
|
|
1521
|
-
*/
|
|
1522
|
-
resetDeficit(tenantId: string): Promise<void>;
|
|
1523
|
-
/**
|
|
1524
|
-
* Get all tenant deficits.
|
|
1525
|
-
*/
|
|
1526
|
-
getAllDeficits(): Promise<Map<string, number>>;
|
|
1287
|
+
resetDeficit(tenantId: string): Promise<void>;
|
|
1288
|
+
/**
|
|
1289
|
+
* Get all tenant deficits.
|
|
1290
|
+
*/
|
|
1291
|
+
getAllDeficits(): Promise<Map<string, number>>;
|
|
1527
1292
|
}
|
|
1528
1293
|
declare module "@internal/redis" {
|
|
1529
1294
|
interface RedisCommander<Context> {
|
|
@@ -1925,6 +1690,258 @@ declare class TenantDispatch {
|
|
|
1925
1690
|
close(): Promise<void>;
|
|
1926
1691
|
}
|
|
1927
1692
|
|
|
1693
|
+
interface VisibilityManagerOptions {
|
|
1694
|
+
redis: RedisOptions;
|
|
1695
|
+
keys: FairQueueKeyProducer;
|
|
1696
|
+
shardCount: number;
|
|
1697
|
+
defaultTimeoutMs: number;
|
|
1698
|
+
logger?: {
|
|
1699
|
+
debug: (message: string, context?: Record<string, unknown>) => void;
|
|
1700
|
+
error: (message: string, context?: Record<string, unknown>) => void;
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
/**
|
|
1704
|
+
* VisibilityManager handles message visibility timeouts for safe message processing.
|
|
1705
|
+
*
|
|
1706
|
+
* Features:
|
|
1707
|
+
* - Claim messages with visibility timeout
|
|
1708
|
+
* - Heartbeat to extend timeout
|
|
1709
|
+
* - Automatic reclaim of timed-out messages
|
|
1710
|
+
* - Per-shard in-flight tracking
|
|
1711
|
+
*
|
|
1712
|
+
* Data structures:
|
|
1713
|
+
* - In-flight sorted set: score = deadline timestamp, member = "{messageId}:{queueId}"
|
|
1714
|
+
* - In-flight data hash: field = messageId, value = JSON message data
|
|
1715
|
+
*/
|
|
1716
|
+
declare class VisibilityManager {
|
|
1717
|
+
#private;
|
|
1718
|
+
private options;
|
|
1719
|
+
private redis;
|
|
1720
|
+
private keys;
|
|
1721
|
+
private shardCount;
|
|
1722
|
+
private defaultTimeoutMs;
|
|
1723
|
+
private logger;
|
|
1724
|
+
constructor(options: VisibilityManagerOptions);
|
|
1725
|
+
/**
|
|
1726
|
+
* Claim a message for processing.
|
|
1727
|
+
* Moves the message from its queue to the in-flight set with a visibility timeout.
|
|
1728
|
+
*
|
|
1729
|
+
* @param queueId - The queue to claim from
|
|
1730
|
+
* @param queueKey - The Redis key for the queue sorted set
|
|
1731
|
+
* @param queueItemsKey - The Redis key for the queue items hash
|
|
1732
|
+
* @param consumerId - ID of the consumer claiming the message
|
|
1733
|
+
* @param timeoutMs - Visibility timeout in milliseconds
|
|
1734
|
+
* @returns Claim result with the message if successful
|
|
1735
|
+
*/
|
|
1736
|
+
claim<TPayload = unknown>(queueId: string, queueKey: string, queueItemsKey: string, consumerId: string, timeoutMs?: number): Promise<ClaimResult<TPayload>>;
|
|
1737
|
+
/**
|
|
1738
|
+
* Claim multiple messages for processing (batch claim).
|
|
1739
|
+
* Moves up to maxCount messages from the queue to the in-flight set.
|
|
1740
|
+
*
|
|
1741
|
+
* @param queueId - The queue to claim from
|
|
1742
|
+
* @param queueKey - The Redis key for the queue sorted set
|
|
1743
|
+
* @param queueItemsKey - The Redis key for the queue items hash
|
|
1744
|
+
* @param consumerId - ID of the consumer claiming the messages
|
|
1745
|
+
* @param maxCount - Maximum number of messages to claim
|
|
1746
|
+
* @param timeoutMs - Visibility timeout in milliseconds
|
|
1747
|
+
* @returns Array of claimed messages
|
|
1748
|
+
*/
|
|
1749
|
+
claimBatch<TPayload = unknown>(queueId: string, queueKey: string, queueItemsKey: string, consumerId: string, maxCount: number, timeoutMs?: number): Promise<Array<InFlightMessage<TPayload>>>;
|
|
1750
|
+
/**
|
|
1751
|
+
* Extend the visibility timeout for a message (heartbeat).
|
|
1752
|
+
*
|
|
1753
|
+
* @param messageId - The message ID
|
|
1754
|
+
* @param queueId - The queue ID
|
|
1755
|
+
* @param extendMs - Additional milliseconds to add to the deadline
|
|
1756
|
+
* @returns true if the heartbeat was successful
|
|
1757
|
+
*/
|
|
1758
|
+
heartbeat(messageId: string, queueId: string, extendMs: number): Promise<boolean>;
|
|
1759
|
+
/**
|
|
1760
|
+
* Mark a message as successfully processed.
|
|
1761
|
+
* Removes the message from in-flight tracking.
|
|
1762
|
+
*
|
|
1763
|
+
* @param messageId - The message ID
|
|
1764
|
+
* @param queueId - The queue ID
|
|
1765
|
+
*/
|
|
1766
|
+
complete(messageId: string, queueId: string): Promise<void>;
|
|
1767
|
+
/**
|
|
1768
|
+
* Release a message back to its queue.
|
|
1769
|
+
* Used when processing fails or consumer wants to retry later.
|
|
1770
|
+
*
|
|
1771
|
+
* @param messageId - The message ID
|
|
1772
|
+
* @param queueId - The queue ID
|
|
1773
|
+
* @param queueKey - The Redis key for the queue
|
|
1774
|
+
* @param queueItemsKey - The Redis key for the queue items hash
|
|
1775
|
+
* @param tenantQueueIndexKey - The Redis key for the tenant queue index (Level 2)
|
|
1776
|
+
* @param dispatchKey - The Redis key for the dispatch index (Level 1)
|
|
1777
|
+
* @param tenantId - The tenant ID
|
|
1778
|
+
* @param score - Optional score for the message (defaults to now)
|
|
1779
|
+
*/
|
|
1780
|
+
release<_TPayload = unknown>(messageId: string, queueId: string, queueKey: string, queueItemsKey: string, tenantQueueIndexKey: string, dispatchKey: string, tenantId: string, score?: number, updatedData?: string): Promise<void>;
|
|
1781
|
+
/**
|
|
1782
|
+
* Release multiple messages back to their queue in a single operation.
|
|
1783
|
+
* Used when processing fails or consumer wants to retry later.
|
|
1784
|
+
* All messages must belong to the same queue.
|
|
1785
|
+
*
|
|
1786
|
+
* @param messages - Array of messages to release (must all have same queueId)
|
|
1787
|
+
* @param queueId - The queue ID
|
|
1788
|
+
* @param queueKey - The Redis key for the queue
|
|
1789
|
+
* @param queueItemsKey - The Redis key for the queue items hash
|
|
1790
|
+
* @param tenantQueueIndexKey - The Redis key for the tenant queue index (Level 2)
|
|
1791
|
+
* @param dispatchKey - The Redis key for the dispatch index (Level 1)
|
|
1792
|
+
* @param tenantId - The tenant ID
|
|
1793
|
+
* @param score - Optional score for the messages (defaults to now)
|
|
1794
|
+
*/
|
|
1795
|
+
releaseBatch(messages: Array<{
|
|
1796
|
+
messageId: string;
|
|
1797
|
+
}>, queueId: string, queueKey: string, queueItemsKey: string, tenantQueueIndexKey: string, dispatchKey: string, tenantId: string, score?: number): Promise<void>;
|
|
1798
|
+
/**
|
|
1799
|
+
* Reclaim timed-out messages from a shard.
|
|
1800
|
+
* Returns messages to their original queues.
|
|
1801
|
+
*
|
|
1802
|
+
* @param shardId - The shard to check
|
|
1803
|
+
* @param getQueueKeys - Function to get queue keys for a queue ID
|
|
1804
|
+
* @returns Array of reclaimed message info for concurrency release
|
|
1805
|
+
*/
|
|
1806
|
+
reclaimTimedOut(shardId: number, getQueueKeys: (queueId: string) => {
|
|
1807
|
+
queueKey: string;
|
|
1808
|
+
queueItemsKey: string;
|
|
1809
|
+
tenantQueueIndexKey: string;
|
|
1810
|
+
dispatchKey: string;
|
|
1811
|
+
tenantId: string;
|
|
1812
|
+
}): Promise<ReclaimedMessageInfo[]>;
|
|
1813
|
+
/**
|
|
1814
|
+
* Get all in-flight messages for a shard.
|
|
1815
|
+
*/
|
|
1816
|
+
getInflightMessages(shardId: number): Promise<Array<{
|
|
1817
|
+
messageId: string;
|
|
1818
|
+
queueId: string;
|
|
1819
|
+
deadline: number;
|
|
1820
|
+
}>>;
|
|
1821
|
+
/**
|
|
1822
|
+
* Get count of in-flight messages for a shard.
|
|
1823
|
+
*/
|
|
1824
|
+
getInflightCount(shardId: number): Promise<number>;
|
|
1825
|
+
/**
|
|
1826
|
+
* Get total in-flight count across all shards.
|
|
1827
|
+
*/
|
|
1828
|
+
getTotalInflightCount(): Promise<number>;
|
|
1829
|
+
/**
|
|
1830
|
+
* Close the Redis connection.
|
|
1831
|
+
*/
|
|
1832
|
+
close(): Promise<void>;
|
|
1833
|
+
}
|
|
1834
|
+
declare module "@internal/redis" {
|
|
1835
|
+
interface RedisCommander<Context> {
|
|
1836
|
+
claimMessage(queueKey: string, queueItemsKey: string, inflightKey: string, inflightDataKey: string, queueId: string, consumerId: string, deadline: string): Promise<[string, string] | null>;
|
|
1837
|
+
claimMessageBatch(queueKey: string, queueItemsKey: string, inflightKey: string, inflightDataKey: string, queueId: string, deadline: string, maxCount: string): Promise<string[]>;
|
|
1838
|
+
releaseMessage(inflightKey: string, inflightDataKey: string, queueKey: string, queueItemsKey: string, tenantQueueIndexKey: string, dispatchKey: string, member: string, messageId: string, score: string, queueId: string, updatedData: string, tenantId: string): Promise<number>;
|
|
1839
|
+
releaseMessageBatch(inflightKey: string, inflightDataKey: string, queueKey: string, queueItemsKey: string, tenantQueueIndexKey: string, dispatchKey: string, score: string, queueId: string, tenantId: string, ...membersAndMessageIds: string[]): Promise<number>;
|
|
1840
|
+
heartbeatMessage(inflightKey: string, member: string, newDeadline: string): Promise<number>;
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
interface WorkerQueueManagerOptions {
|
|
1845
|
+
redis: RedisOptions;
|
|
1846
|
+
keys: FairQueueKeyProducer;
|
|
1847
|
+
logger?: {
|
|
1848
|
+
debug: (message: string, context?: Record<string, unknown>) => void;
|
|
1849
|
+
error: (message: string, context?: Record<string, unknown>) => void;
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* WorkerQueueManager handles the intermediate worker queue layer.
|
|
1854
|
+
*
|
|
1855
|
+
* This provides:
|
|
1856
|
+
* - Low-latency message delivery via blocking pop (BLPOP)
|
|
1857
|
+
* - Routing of messages to specific workers/consumers
|
|
1858
|
+
* - Efficient waiting without polling
|
|
1859
|
+
*
|
|
1860
|
+
* Flow:
|
|
1861
|
+
* 1. Master queue consumer claims message from message queue
|
|
1862
|
+
* 2. Message key is pushed to worker queue
|
|
1863
|
+
* 3. Worker queue consumer does blocking pop to receive message
|
|
1864
|
+
*/
|
|
1865
|
+
declare class WorkerQueueManager {
|
|
1866
|
+
#private;
|
|
1867
|
+
private options;
|
|
1868
|
+
private redis;
|
|
1869
|
+
private keys;
|
|
1870
|
+
private logger;
|
|
1871
|
+
constructor(options: WorkerQueueManagerOptions);
|
|
1872
|
+
/**
|
|
1873
|
+
* Push a message key to a worker queue.
|
|
1874
|
+
* Called after claiming a message from the message queue.
|
|
1875
|
+
*
|
|
1876
|
+
* @param workerQueueId - The worker queue identifier
|
|
1877
|
+
* @param messageKey - The message key to push (typically "messageId:queueId")
|
|
1878
|
+
*/
|
|
1879
|
+
push(workerQueueId: string, messageKey: string): Promise<void>;
|
|
1880
|
+
/**
|
|
1881
|
+
* Push multiple message keys to a worker queue.
|
|
1882
|
+
*
|
|
1883
|
+
* @param workerQueueId - The worker queue identifier
|
|
1884
|
+
* @param messageKeys - The message keys to push
|
|
1885
|
+
*/
|
|
1886
|
+
pushBatch(workerQueueId: string, messageKeys: string[]): Promise<void>;
|
|
1887
|
+
/**
|
|
1888
|
+
* Blocking pop from a worker queue.
|
|
1889
|
+
* Waits until a message is available or timeout expires.
|
|
1890
|
+
*
|
|
1891
|
+
* @param workerQueueId - The worker queue identifier
|
|
1892
|
+
* @param timeoutSeconds - Maximum time to wait (0 = wait forever)
|
|
1893
|
+
* @param signal - Optional abort signal to cancel waiting
|
|
1894
|
+
* @returns The message key, or null if timeout
|
|
1895
|
+
*/
|
|
1896
|
+
blockingPop(workerQueueId: string, timeoutSeconds: number, signal?: AbortSignal): Promise<string | null>;
|
|
1897
|
+
/**
|
|
1898
|
+
* Non-blocking pop from a worker queue.
|
|
1899
|
+
*
|
|
1900
|
+
* @param workerQueueId - The worker queue identifier
|
|
1901
|
+
* @returns The message key and queue length, or null if empty
|
|
1902
|
+
*/
|
|
1903
|
+
pop(workerQueueId: string): Promise<{
|
|
1904
|
+
messageKey: string;
|
|
1905
|
+
queueLength: number;
|
|
1906
|
+
} | null>;
|
|
1907
|
+
/**
|
|
1908
|
+
* Get the current length of a worker queue.
|
|
1909
|
+
*/
|
|
1910
|
+
getLength(workerQueueId: string): Promise<number>;
|
|
1911
|
+
/**
|
|
1912
|
+
* Peek at all messages in a worker queue without removing them.
|
|
1913
|
+
* Useful for debugging and tests.
|
|
1914
|
+
*/
|
|
1915
|
+
peek(workerQueueId: string): Promise<string[]>;
|
|
1916
|
+
/**
|
|
1917
|
+
* Remove a specific message from the worker queue.
|
|
1918
|
+
* Used when a message needs to be removed without processing.
|
|
1919
|
+
*
|
|
1920
|
+
* @param workerQueueId - The worker queue identifier
|
|
1921
|
+
* @param messageKey - The message key to remove
|
|
1922
|
+
* @returns Number of removed items
|
|
1923
|
+
*/
|
|
1924
|
+
remove(workerQueueId: string, messageKey: string): Promise<number>;
|
|
1925
|
+
/**
|
|
1926
|
+
* Clear all messages from a worker queue.
|
|
1927
|
+
*/
|
|
1928
|
+
clear(workerQueueId: string): Promise<void>;
|
|
1929
|
+
/**
|
|
1930
|
+
* Close the Redis connection.
|
|
1931
|
+
*/
|
|
1932
|
+
close(): Promise<void>;
|
|
1933
|
+
/**
|
|
1934
|
+
* Register custom commands on an external Redis client.
|
|
1935
|
+
* Use this when initializing FairQueue with worker queues.
|
|
1936
|
+
*/
|
|
1937
|
+
registerCommands(redis: Redis): void;
|
|
1938
|
+
}
|
|
1939
|
+
declare module "@internal/redis" {
|
|
1940
|
+
interface RedisCommander<Context> {
|
|
1941
|
+
popWithLength(workerQueueKey: string): Promise<[string, string] | null>;
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1928
1945
|
/**
|
|
1929
1946
|
* FairQueue is the main orchestrator for fair queue message routing.
|
|
1930
1947
|
*
|