redis-smq 8.3.0 → 8.3.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cjs/src/common/redis-client/scripts/lua/acknowledge-message.lua +19 -8
  3. package/dist/cjs/src/common/redis-client/scripts/lua/create-queue.lua +15 -10
  4. package/dist/cjs/src/common/redis-client/scripts/lua/delete-consumer-group.lua +20 -9
  5. package/dist/cjs/src/common/redis-client/scripts/lua/delete-message.lua +90 -147
  6. package/dist/cjs/src/common/redis-client/scripts/lua/fetch-message-for-processing.lua +11 -3
  7. package/dist/cjs/src/common/redis-client/scripts/lua/handle-processing-queue.lua +53 -82
  8. package/dist/cjs/src/common/redis-client/scripts/lua/has-queue-rate-exceeded.lua +15 -8
  9. package/dist/cjs/src/common/redis-client/scripts/lua/init-consumer-queue.lua +12 -8
  10. package/dist/cjs/src/common/redis-client/scripts/lua/publish-message.lua +19 -18
  11. package/dist/cjs/src/common/redis-client/scripts/lua/publish-scheduled-message.lua +89 -119
  12. package/dist/cjs/src/common/redis-client/scripts/lua/requeue-message.lua +54 -53
  13. package/dist/cjs/src/common/redis-client/scripts/lua/schedule-message.lua +47 -76
  14. package/dist/cjs/src/common/redis-client/scripts/lua/set-queue-rate-limit.lua +4 -5
  15. package/dist/cjs/src/common/redis-client/scripts/scripts.d.ts +0 -2
  16. package/dist/cjs/src/common/redis-client/scripts/scripts.d.ts.map +1 -1
  17. package/dist/cjs/src/common/redis-client/scripts/scripts.js +0 -2
  18. package/dist/cjs/src/common/redis-client/scripts/scripts.js.map +1 -1
  19. package/dist/esm/src/common/redis-client/scripts/lua/acknowledge-message.lua +19 -8
  20. package/dist/esm/src/common/redis-client/scripts/lua/create-queue.lua +15 -10
  21. package/dist/esm/src/common/redis-client/scripts/lua/delete-consumer-group.lua +20 -9
  22. package/dist/esm/src/common/redis-client/scripts/lua/delete-message.lua +90 -147
  23. package/dist/esm/src/common/redis-client/scripts/lua/fetch-message-for-processing.lua +11 -3
  24. package/dist/esm/src/common/redis-client/scripts/lua/handle-processing-queue.lua +53 -82
  25. package/dist/esm/src/common/redis-client/scripts/lua/has-queue-rate-exceeded.lua +15 -8
  26. package/dist/esm/src/common/redis-client/scripts/lua/init-consumer-queue.lua +12 -8
  27. package/dist/esm/src/common/redis-client/scripts/lua/publish-message.lua +19 -18
  28. package/dist/esm/src/common/redis-client/scripts/lua/publish-scheduled-message.lua +89 -119
  29. package/dist/esm/src/common/redis-client/scripts/lua/requeue-message.lua +54 -53
  30. package/dist/esm/src/common/redis-client/scripts/lua/schedule-message.lua +47 -76
  31. package/dist/esm/src/common/redis-client/scripts/lua/set-queue-rate-limit.lua +4 -5
  32. package/dist/esm/src/common/redis-client/scripts/scripts.d.ts +0 -2
  33. package/dist/esm/src/common/redis-client/scripts/scripts.d.ts.map +1 -1
  34. package/dist/esm/src/common/redis-client/scripts/scripts.js +0 -2
  35. package/dist/esm/src/common/redis-client/scripts/scripts.js.map +1 -1
  36. package/package.json +2 -2
  37. package/dist/cjs/src/common/redis-client/scripts/lua/cleanup-offline-consumer.lua +0 -33
  38. package/dist/cjs/src/common/redis-client/scripts/lua/delete-queue-messages.lua +0 -21
  39. package/dist/esm/src/common/redis-client/scripts/lua/cleanup-offline-consumer.lua +0 -33
  40. package/dist/esm/src/common/redis-client/scripts/lua/delete-queue-messages.lua +0 -21
package/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [8.3.1](https://github.com/weyoss/redis-smq/compare/v8.3.0...v8.3.1) (2025-05-06)
7
+
8
+ ### ⚡ Performance Improvements
9
+
10
+ - **redis-smq:** optimize and clean up LUA scripts for better Redis performance ([1f8b128](https://github.com/weyoss/redis-smq/commit/1f8b128716e2686bd7d145efaef9b0c9a28daa65))
11
+
6
12
  ## [8.3.0](https://github.com/weyoss/redis-smq/compare/v8.2.1...v8.3.0) (2025-05-04)
7
13
 
8
14
  ### 🐛 Bug Fixes
@@ -2,27 +2,38 @@ local keyQueueProcessing = KEYS[1]
2
2
  local keyQueueAcknowledged = KEYS[2]
3
3
  local keyMessage = KEYS[3]
4
4
 
5
- ---
6
-
7
5
  local EMessagePropertyStatus = ARGV[1]
8
6
  local EMessagePropertyStatusAcknowledged = ARGV[2]
9
7
  local storeMessages = ARGV[3]
10
8
  local expireStoredMessages = ARGV[4]
11
9
  local storedMessagesSize = ARGV[5]
12
10
 
13
- local function updateMessageStatus()
14
- redis.call("HMSET", keyMessage, EMessagePropertyStatus, EMessagePropertyStatusAcknowledged)
11
+ -- Get the message ID from the processing queue
12
+ local messageId = redis.call("LPOP", keyQueueProcessing)
13
+
14
+ -- If no message was found, return early
15
+ if messageId == false then
16
+ return nil
15
17
  end
16
18
 
17
- local messageId = redis.call("LPOP", keyQueueProcessing)
19
+ -- Update message status immediately
20
+ redis.call("HSET", keyMessage, EMessagePropertyStatus, EMessagePropertyStatusAcknowledged)
21
+
22
+ -- Only perform storage operations if needed
18
23
  if storeMessages == '1' then
24
+ -- Add to acknowledged queue
19
25
  redis.call("RPUSH", keyQueueAcknowledged, messageId)
26
+
27
+ -- Apply expiration if configured
20
28
  if expireStoredMessages ~= '0' then
21
29
  redis.call("PEXPIRE", keyQueueAcknowledged, expireStoredMessages)
22
30
  end
31
+
32
+ -- Trim the queue if size limit is set
23
33
  if storedMessagesSize ~= '0' then
24
- local result = redis.call("LTRIM", keyQueueAcknowledged, storedMessagesSize, -1)
25
- return result
34
+ -- storedMessagesSize should be negative for proper trimming (to keep newest messages)
35
+ redis.call("LTRIM", keyQueueAcknowledged, storedMessagesSize, -1)
26
36
  end
27
37
  end
28
- updateMessageStatus()
38
+
39
+ return messageId
@@ -3,8 +3,6 @@ local keyNsQueues = KEYS[2]
3
3
  local keyQueues = KEYS[3]
4
4
  local keyQueueProperties = KEYS[4]
5
5
 
6
- ---
7
-
8
6
  local namespace = ARGV[1]
9
7
  local queue = ARGV[2]
10
8
  local queuePropertiesQueueType = ARGV[3]
@@ -12,12 +10,19 @@ local queueType = ARGV[4]
12
10
  local queuePropertiesQueueDeliveryModel = ARGV[5]
13
11
  local deliveryModel = ARGV[6]
14
12
 
15
- if redis.call("SISMEMBER", keyQueues, queue) == 0 then
16
- redis.call("SADD", keyQueues, queue)
17
- redis.call("SADD", keyNsQueues, queue)
18
- redis.call("SADD", keyNamespaces, namespace)
19
- redis.call("HSET", keyQueueProperties, queuePropertiesQueueType, queueType)
20
- redis.call("HSET", keyQueueProperties, queuePropertiesQueueDeliveryModel, deliveryModel)
21
- return 'OK'
13
+ -- Check if queue already exists
14
+ if redis.call("SISMEMBER", keyQueues, queue) == 1 then
15
+ return 'QUEUE_EXISTS'
22
16
  end
23
- return 'QUEUE_EXISTS'
17
+
18
+ --
19
+ redis.call("SADD", keyQueues, queue)
20
+ redis.call("SADD", keyNsQueues, queue)
21
+ redis.call("SADD", keyNamespaces, namespace)
22
+
23
+ --
24
+ redis.call("HSET", keyQueueProperties,
25
+ queuePropertiesQueueType, queueType,
26
+ queuePropertiesQueueDeliveryModel, deliveryModel)
27
+
28
+ return 'OK'
@@ -9,26 +9,37 @@ local typeLIFOQueue = ARGV[3]
9
9
  local typeFIFOQueue = ARGV[4]
10
10
  local groupId = ARGV[5]
11
11
 
12
+ -- Get queue type once and validate it exists
12
13
  local queueType = redis.call("HGET", keyQueueProperties, queuePropertiesQueueType)
13
14
  if queueType == false then
14
15
  return 'QUEUE_NOT_FOUND'
15
16
  end
16
17
 
17
- local count = 0;
18
+ -- Determine which key to check based on queue type (only once)
19
+ local pendingKey
18
20
  if queueType == typePriorityQueue then
19
- count = redis.call("ZCARD", keyQueuePendingPriority)
20
- elseif queueType == typeLIFOQueue or queueType == typeFIFOQueue then
21
- count = redis.call("LLEN", keyQueuePending)
21
+ pendingKey = keyQueuePendingPriority
22
+ else
23
+ pendingKey = keyQueuePending
22
24
  end
25
+
26
+ -- Check if the queue is empty using the appropriate command
27
+ local count = 0
28
+ if queueType == typePriorityQueue then
29
+ count = redis.call("ZCARD", pendingKey)
30
+ else
31
+ count = redis.call("LLEN", pendingKey)
32
+ end
33
+
34
+ -- Return early if the queue is not empty
23
35
  if count > 0 then
24
36
  return 'CONSUMER_GROUP_NOT_EMPTY'
25
37
  end
26
38
 
39
+ -- Remove the consumer group
27
40
  redis.call("SREM", keyQueueConsumerGroups, groupId)
28
- if queueType == typePriorityQueue then
29
- redis.call("DEL", keyQueuePendingPriority)
30
- elseif queueType == typeLIFOQueue or queueType == typeFIFOQueue then
31
- redis.call("DEL", keyQueuePending)
32
- end
41
+
42
+ -- Delete the pending queue
43
+ redis.call("DEL", pendingKey)
33
44
 
34
45
  return 'OK'
@@ -1,161 +1,104 @@
1
- -- Constants for queue properties and message statuses
2
- local EQueuePropertyQueueType = ARGV[1]
3
- local EQueuePropertyMessagesCount = ARGV[2]
4
- local EQueuePropertyQueueTypePriorityQueue = ARGV[3]
5
- local EQueuePropertyQueueTypeLIFOQueue = ARGV[4]
6
- local EQueuePropertyQueueTypeFIFOQueue = ARGV[5]
7
- local EMessagePropertyStatus = ARGV[6]
8
- local EMessagePropertyStatusProcessing = ARGV[7]
9
- local EMessagePropertyStatusAcknowledged = ARGV[8]
10
- local EMessagePropertyStatusPending = ARGV[9]
11
- local EMessagePropertyStatusScheduled = ARGV[10]
12
- local EMessagePropertyStatusDeadLettered = ARGV[11]
13
- local EMessagePropertyStatusUnackDelaying = ARGV[12]
14
- local EMessagePropertyStatusUnackRequeuing = ARGV[13]
15
-
16
- -- Response status constants
17
- local STATUS = {
18
- OK = 'OK',
19
- MESSAGE_NOT_FOUND = 'MESSAGE_NOT_FOUND',
20
- MESSAGE_IN_PROCESS = 'MESSAGE_IN_PROCESS',
21
- INVALID_PARAMETERS = 'INVALID_PARAMETERS',
22
- PARTIAL_SUCCESS = 'PARTIAL_SUCCESS'
23
- }
24
-
25
- -- Key placeholders
26
- local keys = {
27
- queueScheduled = '',
28
- queueDelayed = '',
29
- queueRequeued = '',
30
- message = '',
31
- queueProperties = '',
32
- queuePending = '',
33
- queueDL = '',
34
- queueAcknowledged = '',
35
- queuePriorityPending = '',
36
- queueMessages = '',
37
- }
38
-
39
- -- Offset trackers
40
- local keyIndexOffset = 0
41
- local argvIndexOffset = 13
42
-
43
- -- Removes a message from the corresponding queue (scheduled, acknowledged, delayed, requeue, pending) based on status
44
- local function removeFromStatusQueue(messageId, messageStatus)
45
- local deleted = 0
46
-
47
- if messageStatus == EMessagePropertyStatusAcknowledged then
48
- deleted = redis.call("LREM", keys.queueAcknowledged, 1, messageId)
49
- elseif messageStatus == EMessagePropertyStatusDeadLettered then
50
- deleted = redis.call("LREM", keys.queueDL, 1, messageId)
51
- elseif messageStatus == EMessagePropertyStatusScheduled then
52
- deleted = redis.call("ZREM", keys.queueScheduled, messageId)
53
- elseif messageStatus == EMessagePropertyStatusUnackDelaying then
54
- deleted = redis.call("LREM", keys.queueDelayed, 1, messageId)
55
- elseif messageStatus == EMessagePropertyStatusUnackRequeuing then
56
- deleted = redis.call("LREM", keys.queueRequeued, 1, messageId)
57
- elseif messageStatus == EMessagePropertyStatusPending then
58
- local queueType = redis.call("HGET", keys.queueProperties, EQueuePropertyQueueType)
59
- if queueType then
60
- if queueType == EQueuePropertyQueueTypePriorityQueue then
61
- deleted = redis.call("ZREM", keys.queuePriorityPending, messageId)
62
- elseif queueType == EQueuePropertyQueueTypeFIFOQueue or queueType == EQueuePropertyQueueTypeLIFOQueue then
63
- deleted = redis.call("LREM", keys.queuePending, 1, messageId)
64
- end
65
- end
66
- end
67
-
68
- return deleted
1
+ local QUEUE_TYPE = ARGV[1]
2
+ local MSG_COUNT = ARGV[2]
3
+ local QUEUE_TYPE_PRIORITY = ARGV[3]
4
+ local QUEUE_TYPE_LIFO = ARGV[4]
5
+ local QUEUE_TYPE_FIFO = ARGV[5]
6
+ local MSG_STATUS = ARGV[6]
7
+ local MSG_STATUS_PROCESSING = ARGV[7]
8
+ local MSG_STATUS_ACKNOWLEDGED = ARGV[8]
9
+ local MSG_STATUS_PENDING = ARGV[9]
10
+ local MSG_STATUS_SCHEDULED = ARGV[10]
11
+ local MSG_STATUS_DEADLETTERED = ARGV[11]
12
+ local MSG_STATUS_UNACK_DELAYING = ARGV[12]
13
+ local MSG_STATUS_UNACK_REQUEUING = ARGV[13]
14
+
15
+ local STATUS_OK = 'OK'
16
+ local STATUS_MESSAGE_NOT_FOUND = 'MESSAGE_NOT_FOUND'
17
+ local STATUS_MESSAGE_IN_PROCESS = 'MESSAGE_IN_PROCESS'
18
+ local STATUS_INVALID_PARAMETERS = 'INVALID_PARAMETERS'
19
+
20
+ -- Counters for tracking results
21
+ local processedCount = 0
22
+ local successCount = 0
23
+ local notFoundCount = 0
24
+ local inProcessCount = 0
25
+
26
+ -- Constants for parameter counts
27
+ local INITIAL_KEY_OFFSET = 0
28
+ local INITIAL_ARGV_OFFSET = 13
29
+ local PARAMS_PER_MESSAGE = 1
30
+ local KEYS_PER_MESSAGE = 10
31
+
32
+ -- Validate parameters
33
+ if #ARGV <= INITIAL_ARGV_OFFSET then
34
+ return 'INVALID_PARAMETERS'
69
35
  end
70
36
 
71
- -- Deletes a message and returns the status
72
- local function deleteMessage(messageId)
73
- -- Check if message exists and get its status
74
- local messageStatus = redis.call("HGET", keys.message, EMessagePropertyStatus)
75
- if not messageStatus then
76
- return STATUS.MESSAGE_NOT_FOUND
77
- end
78
-
79
- -- For messages in process, we'll just report the status but not attempt deletion
80
- if messageStatus == EMessagePropertyStatusProcessing then
81
- return STATUS.MESSAGE_IN_PROCESS
82
- end
37
+ --
38
+ local keyIndex = INITIAL_KEY_OFFSET + 1
83
39
 
84
- -- Try to remove the message from acknowledged, dl, scheduled, etc. based on message status
85
- removeFromStatusQueue(messageId, messageStatus)
40
+ for argvIndex = INITIAL_ARGV_OFFSET + 1, #ARGV, PARAMS_PER_MESSAGE do
41
+ local messageId = ARGV[argvIndex]
86
42
 
87
- -- Delete the message
88
- redis.call("DEL", keys.message)
43
+ -- Setup direct key references for this message
44
+ local queueScheduled = KEYS[keyIndex]
45
+ local queueDelayed = KEYS[keyIndex + 1]
46
+ local queueRequeued = KEYS[keyIndex + 2]
47
+ local messageKey = KEYS[keyIndex + 3]
48
+ local queueProperties = KEYS[keyIndex + 4]
49
+ local queuePending = KEYS[keyIndex + 5]
50
+ local queueDL = KEYS[keyIndex + 6]
51
+ local queueAcknowledged = KEYS[keyIndex + 7]
52
+ local queuePriorityPending = KEYS[keyIndex + 8]
53
+ local queueMessages = KEYS[keyIndex + 9]
89
54
 
90
- -- Remove the message ID from queue messages
91
- redis.call("SREM", keys.queueMessages, messageId)
55
+ -- Update keyIndex for next iteration
56
+ keyIndex = keyIndex + KEYS_PER_MESSAGE
92
57
 
93
- -- Decrements the message count in queue properties
94
- redis.call("HINCRBY", keys.queueProperties, EQueuePropertyMessagesCount, -1)
58
+ --
59
+ processedCount = processedCount + 1
95
60
 
96
- return STATUS.OK
97
- end
98
-
99
- -- Setup keys for a message
100
- local function setupKeysForMessage(baseOffset)
101
- keys.queueScheduled = KEYS[baseOffset + 1]
102
- keys.queueDelayed = KEYS[baseOffset + 2]
103
- keys.queueRequeued = KEYS[baseOffset + 3]
104
- keys.message = KEYS[baseOffset + 4]
105
- keys.queueProperties = KEYS[baseOffset + 5]
106
- keys.queuePending = KEYS[baseOffset + 6]
107
- keys.queueDL = KEYS[baseOffset + 7]
108
- keys.queueAcknowledged = KEYS[baseOffset + 8]
109
- keys.queuePriorityPending = KEYS[baseOffset + 9]
110
- keys.queueMessages = KEYS[baseOffset + 10]
111
- end
112
-
113
- -- Main execution logic
114
- local function main()
115
- -- Counters for tracking results
116
- local processedCount = 0
117
- local successCount = 0
118
- local notFoundCount = 0
119
- local inProcessCount = 0
120
-
121
- -- Check if we have enough arguments
122
- if #ARGV <= argvIndexOffset then
123
- return STATUS.INVALID_PARAMETERS
124
- end
125
-
126
- -- Process each message ID
127
- for i = argvIndexOffset + 1, #ARGV do
128
- local messageId = ARGV[i]
129
- processedCount = processedCount + 1
61
+ -- Check if message exists and get its status
62
+ local messageStatus = redis.call("HGET", messageKey, MSG_STATUS)
63
+ if messageStatus == false then
64
+ notFoundCount = notFoundCount + 1
65
+ elseif messageStatus == MSG_STATUS_PROCESSING then
66
+ inProcessCount = inProcessCount + 1
67
+ else
68
+ -- Remove from appropriate queue based on status
69
+ if messageStatus == MSG_STATUS_ACKNOWLEDGED then
70
+ redis.call("LREM", queueAcknowledged, 1, messageId)
71
+ elseif messageStatus == MSG_STATUS_DEADLETTERED then
72
+ redis.call("LREM", queueDL, 1, messageId)
73
+ elseif messageStatus == MSG_STATUS_SCHEDULED then
74
+ redis.call("ZREM", queueScheduled, messageId)
75
+ elseif messageStatus == MSG_STATUS_UNACK_DELAYING then
76
+ redis.call("LREM", queueDelayed, 1, messageId)
77
+ elseif messageStatus == MSG_STATUS_UNACK_REQUEUING then
78
+ redis.call("LREM", queueRequeued, 1, messageId)
79
+ elseif messageStatus == MSG_STATUS_PENDING then
80
+ local queueType = redis.call("HGET", queueProperties, QUEUE_TYPE)
81
+ if queueType then
82
+ if queueType == QUEUE_TYPE_PRIORITY then
83
+ redis.call("ZREM", queuePriorityPending, messageId)
84
+ elseif queueType == QUEUE_TYPE_FIFO or queueType == QUEUE_TYPE_LIFO then
85
+ redis.call("LREM", queuePending, 1, messageId)
86
+ end
87
+ end
88
+ end
130
89
 
131
- -- Setup keys for this message
132
- setupKeysForMessage(keyIndexOffset)
133
- keyIndexOffset = keyIndexOffset + 10
90
+ -- Delete the message
91
+ redis.call("DEL", messageKey)
134
92
 
135
- -- Try to delete the message
136
- local messageStatus = deleteMessage(messageId)
93
+ -- Remove the message ID from queue messages
94
+ redis.call("SREM", queueMessages, messageId)
137
95
 
138
- -- Track results but continue processing regardless of status
139
- if messageStatus == STATUS.OK then
140
- successCount = successCount + 1
141
- elseif messageStatus == STATUS.MESSAGE_NOT_FOUND then
142
- notFoundCount = notFoundCount + 1
143
- elseif messageStatus == STATUS.MESSAGE_IN_PROCESS then
144
- inProcessCount = inProcessCount + 1
145
- end
96
+ -- Decrements the message count in queue properties
97
+ redis.call("HINCRBY", queueProperties, MSG_COUNT, -1)
146
98
 
147
- -- Always continue to the next message
99
+ successCount = successCount + 1
148
100
  end
149
-
150
- -- Return an array instead of a table for compatibility with Redis
151
- -- Format: [processed, success, notFound, inProcess]
152
- return {
153
- processedCount,
154
- successCount,
155
- notFoundCount,
156
- inProcessCount
157
- }
158
101
  end
159
102
 
160
- -- Execute the main function and return the result
161
- return main()
103
+ -- Return an array with the results
104
+ return {processedCount, successCount, notFoundCount, inProcessCount}
@@ -5,8 +5,16 @@ local EMessagePropertyState = ARGV[2]
5
5
  local EMessagePropertyMessage = ARGV[3]
6
6
  local EMessagePropertyStatusProcessing = ARGV[4]
7
7
 
8
+ -- Fetch only the required fields in a single operation
8
9
  local result = redis.call("HMGET", keyMessage, EMessagePropertyState, EMessagePropertyMessage)
9
- if result[1] ~= false and result[2] ~= false then
10
- redis.call("HSET", keyMessage, EMessagePropertyStatus, EMessagePropertyStatusProcessing)
11
- return result
10
+
11
+ -- Early return if either field is missing
12
+ if result[1] == false or result[2] == false then
13
+ return false
12
14
  end
15
+
16
+ -- Update the message status to processing
17
+ redis.call("HSET", keyMessage, EMessagePropertyStatus, EMessagePropertyStatusProcessing)
18
+
19
+ -- Return the message data
20
+ return result
@@ -8,49 +8,46 @@ local EMessagePropertyStatus = ARGV[7]
8
8
  local EMessageUnacknowledgedCauseOfflineConsumer = ARGV[8]
9
9
  local EMessageUnacknowledgedCauseOfflineHandler = ARGV[9]
10
10
 
11
- ---
11
+ --
12
+ local INITIAL_KEY_OFFSET = 0
13
+ local INITIAL_ARGV_OFFSET = 9
14
+ local PARAMS_PER_MESSAGE = 7
15
+ local KEYS_PER_MESSAGE = 9
12
16
 
13
- local keyIndexOffset = 0
14
- local argvIndexOffset = 9
15
-
16
- ---
17
-
18
- local keyQueueProcessing = ''
19
- local keyQueueDelayed = ''
20
- local keyQueueRequeued = ''
21
- local keyQueueDL = ''
22
- local keyQueueProcessingQueues = ''
23
- local keyQueueConsumers = ''
24
- local keyConsumerQueues = ''
25
- local keyQueueProperties = ''
26
- local keyMessage = ''
17
+ --
18
+ if (#ARGV <= INITIAL_ARGV_OFFSET) then
19
+ return 'INVALID_PARAMETERS'
20
+ end
27
21
 
28
- local queue = ''
29
- local consumerId = ''
30
- local messageId = ''
31
- local retryAction = ''
32
- local messageDeadLetteredCause = ''
33
- local messageUnacknowledgedCause = ''
34
- local messageStatus = ''
22
+ --
23
+ local keyIndex = INITIAL_KEY_OFFSET + 1
35
24
 
36
- ---
25
+ --
26
+ for argvIndex = INITIAL_ARGV_OFFSET + 1, #ARGV, PARAMS_PER_MESSAGE do
27
+ -- Read all values for this group directly
28
+ local queue = ARGV[argvIndex]
29
+ local consumerId = ARGV[argvIndex + 1]
30
+ local messageId = ARGV[argvIndex + 2]
31
+ local retryAction = ARGV[argvIndex + 3]
32
+ local messageDeadLetteredCause = ARGV[argvIndex + 4]
33
+ local messageUnacknowledgedCause = ARGV[argvIndex + 5]
34
+ local messageStatus = ARGV[argvIndex + 6]
37
35
 
38
- local function updateMessageStatus()
39
- redis.call("HMSET", keyMessage, EMessagePropertyStatus, messageStatus)
40
- end
36
+ -- Get keys for this group directly
37
+ local keyQueueProcessing = KEYS[keyIndex]
38
+ local keyQueueDelayed = KEYS[keyIndex + 1]
39
+ local keyQueueRequeued = KEYS[keyIndex + 2]
40
+ local keyQueueDL = KEYS[keyIndex + 3]
41
+ local keyQueueProcessingQueues = KEYS[keyIndex + 4]
42
+ local keyQueueConsumers = KEYS[keyIndex + 5]
43
+ local keyConsumerQueues = KEYS[keyIndex + 6]
44
+ local keyQueueProperties = KEYS[keyIndex + 7]
45
+ local keyMessage = KEYS[keyIndex + 8]
41
46
 
42
- local function removeQueueConsumer()
43
- if queue ~= '' then
44
- redis.call("HDEL", keyQueueConsumers, consumerId)
45
- redis.call("SREM", keyConsumerQueues, queue)
46
- local size = redis.call("SCARD", keyConsumerQueues)
47
- if size == 0 then
48
- redis.call("DEL", keyConsumerQueues)
49
- end
50
- end
51
- end
47
+ -- Update keyIndex for next iteration
48
+ keyIndex = keyIndex + KEYS_PER_MESSAGE
52
49
 
53
- local function retryMessage()
50
+ -- Process message
54
51
  if messageId ~= '' then
55
52
  if retryAction == ERetryActionRequeue then
56
53
  redis.call("RPOPLPUSH", keyQueueProcessing, keyQueueRequeued)
@@ -64,63 +61,37 @@ local function retryMessage()
64
61
  redis.call("PEXPIRE", keyQueueDL, expireStoredMessages)
65
62
  end
66
63
  if storedMessagesSize ~= '0' then
64
+ -- storedMessagesSize should be negative for proper trimming (to keep newest messages)
67
65
  redis.call("LTRIM", keyQueueDL, storedMessagesSize, -1)
68
66
  end
69
67
  else
70
68
  redis.call("RPOP", keyQueueProcessing)
71
69
  end
72
70
  end
73
- updateMessageStatus();
74
- end
75
- end
76
71
 
77
- local function deleteProcessingQueue()
78
- if keyQueueProcessing ~= '' then
79
- redis.call("HDEL", keyQueueProcessingQueues, keyQueueProcessing)
80
- redis.call("DEL", keyQueueProcessing)
72
+ -- Update message status
73
+ redis.call("HSET", keyMessage, EMessagePropertyStatus, messageStatus)
81
74
  end
82
- end
83
75
 
84
- ---
76
+ -- Handle offline consumer/handler
77
+ if messageUnacknowledgedCause == EMessageUnacknowledgedCauseOfflineConsumer or
78
+ messageUnacknowledgedCause == EMessageUnacknowledgedCauseOfflineHandler then
79
+ -- Delete processing queue
80
+ if keyQueueProcessing ~= '' then
81
+ redis.call("HDEL", keyQueueProcessingQueues, keyQueueProcessing)
82
+ redis.call("DEL", keyQueueProcessing)
83
+ end
85
84
 
86
- if #ARGV > argvIndexOffset then
87
- for index in pairs(ARGV) do
88
- if (index > argvIndexOffset) then
89
- local relativeIndex = index % 7
90
- if relativeIndex == 3 then
91
- queue = ARGV[index]
92
- keyQueueProcessing = KEYS[keyIndexOffset + 1]
93
- keyQueueDelayed = KEYS[keyIndexOffset + 2];
94
- keyQueueRequeued = KEYS[keyIndexOffset + 3];
95
- keyQueueDL = KEYS[keyIndexOffset + 4]
96
- keyQueueProcessingQueues = KEYS[keyIndexOffset + 5]
97
- keyQueueConsumers = KEYS[keyIndexOffset + 6]
98
- keyConsumerQueues = KEYS[keyIndexOffset + 7]
99
- keyQueueProperties = KEYS[keyIndexOffset + 8]
100
- keyMessage = KEYS[keyIndexOffset + 9]
101
- keyIndexOffset = keyIndexOffset + 9
102
- elseif relativeIndex == 4 then
103
- consumerId = ARGV[index]
104
- elseif relativeIndex == 5 then
105
- messageId = ARGV[index]
106
- elseif relativeIndex == 6 then
107
- retryAction = ARGV[index]
108
- elseif relativeIndex == 0 then
109
- messageDeadLetteredCause = ARGV[index]
110
- elseif relativeIndex == 1 then
111
- messageUnacknowledgedCause = ARGV[index]
112
- elseif relativeIndex == 2 then
113
- messageStatus = ARGV[index]
114
- retryMessage()
115
- if messageUnacknowledgedCause == EMessageUnacknowledgedCauseOfflineConsumer or messageUnacknowledgedCause == EMessageUnacknowledgedCauseOfflineHandler then
116
- deleteProcessingQueue()
117
- removeQueueConsumer()
118
- end
85
+ -- Remove queue consumer
86
+ if queue ~= '' then
87
+ redis.call("HDEL", keyQueueConsumers, consumerId)
88
+ redis.call("SREM", keyConsumerQueues, queue)
89
+ local size = redis.call("SCARD", keyConsumerQueues)
90
+ if size == 0 then
91
+ redis.call("DEL", keyConsumerQueues)
119
92
  end
120
93
  end
121
94
  end
122
- return 'OK'
123
95
  end
124
96
 
125
- return 'INVALID_PARAMETERS'
126
-
97
+ return 'OK'
@@ -1,19 +1,26 @@
1
1
  local keyQueueRateLimitCounter = KEYS[1]
2
2
 
3
- ---
3
+ local rateLimitLimit = tonumber(ARGV[1])
4
+ local rateLimitExpire = tonumber(ARGV[2])
4
5
 
5
- local rateLimitLimit = ARGV[1]
6
- local rateLimitExpire = ARGV[2]
6
+ -- Get the current counter value
7
+ local count = redis.call("GET", keyQueueRateLimitCounter)
7
8
 
8
- local result = redis.call("GET", keyQueueRateLimitCounter)
9
- if result == false then
10
- redis.call("SET", keyQueueRateLimitCounter, rateLimitLimit)
11
- redis.call("PEXPIRE", keyQueueRateLimitCounter, rateLimitExpire);
9
+ -- If counter doesn't exist, initialize it
10
+ if count == false then
11
+ -- Use SET with EX option to combine SET and EXPIRE into one command
12
+ redis.call("SET", keyQueueRateLimitCounter, rateLimitLimit, "PX", rateLimitExpire)
12
13
  return 0
13
14
  end
14
- local count = tonumber(result)
15
+
16
+ -- Convert to number
17
+ count = tonumber(count)
18
+
19
+ -- Check if rate limit is exceeded
15
20
  if count <= 1 then
16
21
  return 1
17
22
  end
23
+
24
+ -- Decrement the counter
18
25
  redis.call("DECR", keyQueueRateLimitCounter)
19
26
  return 0
@@ -3,17 +3,21 @@ local keyQueueConsumers = KEYS[2]
3
3
  local keyConsumerQueues = KEYS[3]
4
4
  local keyQueueProcessingQueues = KEYS[4]
5
5
 
6
- ---
7
-
8
6
  local consumerId = ARGV[1]
9
7
  local consumerInfo = ARGV[2]
10
8
  local queue = ARGV[3]
11
9
  local consumerProcessingQueue = ARGV[4]
12
10
 
13
- if redis.call("SISMEMBER", keyQueues, queue) == 1 then
14
- redis.call("SADD", keyConsumerQueues, queue)
15
- redis.call("HSET", keyQueueConsumers, consumerId, consumerInfo)
16
- redis.call("HSET", keyQueueProcessingQueues, consumerProcessingQueue, consumerId)
17
- return 1
11
+ -- Early return if queue doesn't exist
12
+ if redis.call("SISMEMBER", keyQueues, queue) == 0 then
13
+ return 0
18
14
  end
19
- return 0
15
+
16
+ -- Execute all operations in sequence without conditional branching
17
+ redis.call("SADD", keyConsumerQueues, queue)
18
+
19
+ --
20
+ redis.call("HSET", keyQueueConsumers, consumerId, consumerInfo)
21
+ redis.call("HSET", keyQueueProcessingQueues, consumerProcessingQueue, consumerId)
22
+
23
+ return 1