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.
- package/CHANGELOG.md +6 -0
- package/dist/cjs/src/common/redis-client/scripts/lua/acknowledge-message.lua +19 -8
- package/dist/cjs/src/common/redis-client/scripts/lua/create-queue.lua +15 -10
- package/dist/cjs/src/common/redis-client/scripts/lua/delete-consumer-group.lua +20 -9
- package/dist/cjs/src/common/redis-client/scripts/lua/delete-message.lua +90 -147
- package/dist/cjs/src/common/redis-client/scripts/lua/fetch-message-for-processing.lua +11 -3
- package/dist/cjs/src/common/redis-client/scripts/lua/handle-processing-queue.lua +53 -82
- package/dist/cjs/src/common/redis-client/scripts/lua/has-queue-rate-exceeded.lua +15 -8
- package/dist/cjs/src/common/redis-client/scripts/lua/init-consumer-queue.lua +12 -8
- package/dist/cjs/src/common/redis-client/scripts/lua/publish-message.lua +19 -18
- package/dist/cjs/src/common/redis-client/scripts/lua/publish-scheduled-message.lua +89 -119
- package/dist/cjs/src/common/redis-client/scripts/lua/requeue-message.lua +54 -53
- package/dist/cjs/src/common/redis-client/scripts/lua/schedule-message.lua +47 -76
- package/dist/cjs/src/common/redis-client/scripts/lua/set-queue-rate-limit.lua +4 -5
- package/dist/cjs/src/common/redis-client/scripts/scripts.d.ts +0 -2
- package/dist/cjs/src/common/redis-client/scripts/scripts.d.ts.map +1 -1
- package/dist/cjs/src/common/redis-client/scripts/scripts.js +0 -2
- package/dist/cjs/src/common/redis-client/scripts/scripts.js.map +1 -1
- package/dist/esm/src/common/redis-client/scripts/lua/acknowledge-message.lua +19 -8
- package/dist/esm/src/common/redis-client/scripts/lua/create-queue.lua +15 -10
- package/dist/esm/src/common/redis-client/scripts/lua/delete-consumer-group.lua +20 -9
- package/dist/esm/src/common/redis-client/scripts/lua/delete-message.lua +90 -147
- package/dist/esm/src/common/redis-client/scripts/lua/fetch-message-for-processing.lua +11 -3
- package/dist/esm/src/common/redis-client/scripts/lua/handle-processing-queue.lua +53 -82
- package/dist/esm/src/common/redis-client/scripts/lua/has-queue-rate-exceeded.lua +15 -8
- package/dist/esm/src/common/redis-client/scripts/lua/init-consumer-queue.lua +12 -8
- package/dist/esm/src/common/redis-client/scripts/lua/publish-message.lua +19 -18
- package/dist/esm/src/common/redis-client/scripts/lua/publish-scheduled-message.lua +89 -119
- package/dist/esm/src/common/redis-client/scripts/lua/requeue-message.lua +54 -53
- package/dist/esm/src/common/redis-client/scripts/lua/schedule-message.lua +47 -76
- package/dist/esm/src/common/redis-client/scripts/lua/set-queue-rate-limit.lua +4 -5
- package/dist/esm/src/common/redis-client/scripts/scripts.d.ts +0 -2
- package/dist/esm/src/common/redis-client/scripts/scripts.d.ts.map +1 -1
- package/dist/esm/src/common/redis-client/scripts/scripts.js +0 -2
- package/dist/esm/src/common/redis-client/scripts/scripts.js.map +1 -1
- package/package.json +2 -2
- package/dist/cjs/src/common/redis-client/scripts/lua/cleanup-offline-consumer.lua +0 -33
- package/dist/cjs/src/common/redis-client/scripts/lua/delete-queue-messages.lua +0 -21
- package/dist/esm/src/common/redis-client/scripts/lua/cleanup-offline-consumer.lua +0 -33
- 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
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
18
|
+
-- Determine which key to check based on queue type (only once)
|
|
19
|
+
local pendingKey
|
|
18
20
|
if queueType == typePriorityQueue then
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
2
|
-
local
|
|
3
|
-
local
|
|
4
|
-
local
|
|
5
|
-
local
|
|
6
|
-
local
|
|
7
|
-
local
|
|
8
|
-
local
|
|
9
|
-
local
|
|
10
|
-
local
|
|
11
|
-
local
|
|
12
|
-
local
|
|
13
|
-
local
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
local
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
--
|
|
72
|
-
local
|
|
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
|
-
|
|
85
|
-
|
|
40
|
+
for argvIndex = INITIAL_ARGV_OFFSET + 1, #ARGV, PARAMS_PER_MESSAGE do
|
|
41
|
+
local messageId = ARGV[argvIndex]
|
|
86
42
|
|
|
87
|
-
--
|
|
88
|
-
|
|
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
|
-
--
|
|
91
|
-
|
|
55
|
+
-- Update keyIndex for next iteration
|
|
56
|
+
keyIndex = keyIndex + KEYS_PER_MESSAGE
|
|
92
57
|
|
|
93
|
-
--
|
|
94
|
-
|
|
58
|
+
--
|
|
59
|
+
processedCount = processedCount + 1
|
|
95
60
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
--
|
|
132
|
-
|
|
133
|
-
keyIndexOffset = keyIndexOffset + 10
|
|
90
|
+
-- Delete the message
|
|
91
|
+
redis.call("DEL", messageKey)
|
|
134
92
|
|
|
135
|
-
--
|
|
136
|
-
|
|
93
|
+
-- Remove the message ID from queue messages
|
|
94
|
+
redis.call("SREM", queueMessages, messageId)
|
|
137
95
|
|
|
138
|
-
--
|
|
139
|
-
|
|
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
|
-
|
|
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
|
-
--
|
|
161
|
-
return
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
14
|
-
|
|
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
|
-
|
|
29
|
-
local
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
78
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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 '
|
|
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
|
-
|
|
6
|
-
local
|
|
6
|
+
-- Get the current counter value
|
|
7
|
+
local count = redis.call("GET", keyQueueRateLimitCounter)
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
if
|
|
10
|
-
|
|
11
|
-
redis.call("
|
|
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
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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
|