@@ -66,9 +66,11 @@ type RedisCli interface {
6666 SMembers (key string ) ([]string , error )
6767 SRem (key string , members []string ) error
6868 ZAdd (key string , values map [string ]float64 ) error
69- ZRem (key string , fields []string ) error
69+ ZRem (key string , fields []string ) ( int64 , error )
7070 ZCard (key string ) (int64 , error )
71+ ZScore (key string , member string ) (float64 , error )
7172 LLen (key string ) (int64 , error )
73+ LRem (key string , count int64 , value string ) (int64 , error )
7274
7375 // Publish used for monitor only
7476 Publish (channel string , payload string ) error
@@ -206,7 +208,7 @@ func (q *DelayQueue) WithDefaultRetryCount(count uint) *DelayQueue {
206208 return q
207209}
208210
209- // WithNackRedeliveryDelay customizes the interval between redelivery and nack (callback returns false)
211+ // WithNackRedeliveryDelay customizes the interval between redelivery and nack (callback returns false)
210212// If consumption exceeded deadline, the message will be redelivered immediately
211213func (q * DelayQueue ) WithNackRedeliveryDelay (d time.Duration ) * DelayQueue {
212214 q .nackRedeliveryDelay = d
@@ -236,8 +238,25 @@ func WithMsgTTL(d time.Duration) interface{} {
236238 return msgTTLOpt (d )
237239}
238240
239- // SendScheduleMsg submits a message delivered at given time
240- func (q * DelayQueue ) SendScheduleMsg (payload string , t time.Time , opts ... interface {}) error {
241+ // MessageInfo stores information to trace a message
242+ type MessageInfo struct {
243+ id string
244+ }
245+
246+ func (msg * MessageInfo ) ID () string {
247+ return msg .id
248+ }
249+
250+ const (
251+ StatePending = "pending"
252+ StateReady = "ready"
253+ StateReadyRetry = "ready_to_retry"
254+ StateConsuming = "consuming"
255+ StateUnknown = "unknown"
256+ )
257+
258+ // SendScheduleMsgV2 submits a message delivered at given time
259+ func (q * DelayQueue ) SendScheduleMsgV2 (payload string , t time.Time , opts ... interface {}) (* MessageInfo , error ) {
241260 // parse options
242261 retryCount := q .defaultRetryCount
243262 for _ , opt := range opts {
@@ -255,28 +274,90 @@ func (q *DelayQueue) SendScheduleMsg(payload string, t time.Time, opts ...interf
255274 msgTTL := t .Sub (now ) + q .msgTTL // delivery + q.msgTTL
256275 err := q .redisCli .Set (q .genMsgKey (idStr ), payload , msgTTL )
257276 if err != nil {
258- return fmt .Errorf ("store msg failed: %v" , err )
277+ return nil , fmt .Errorf ("store msg failed: %v" , err )
259278 }
260279 // store retry count
261280 err = q .redisCli .HSet (q .retryCountKey , idStr , strconv .Itoa (int (retryCount )))
262281 if err != nil {
263- return fmt .Errorf ("store retry count failed: %v" , err )
282+ return nil , fmt .Errorf ("store retry count failed: %v" , err )
264283 }
265284 // put to pending
266285 err = q .redisCli .ZAdd (q .pendingKey , map [string ]float64 {idStr : float64 (t .Unix ())})
267286 if err != nil {
268- return fmt .Errorf ("push to pending failed: %v" , err )
287+ return nil , fmt .Errorf ("push to pending failed: %v" , err )
269288 }
270289 q .reportEvent (NewMessageEvent , 1 )
271- return nil
290+ return & MessageInfo {
291+ id : idStr ,
292+ }, nil
272293}
273294
274295// SendDelayMsg submits a message delivered after given duration
296+ func (q * DelayQueue ) SendDelayMsgV2 (payload string , duration time.Duration , opts ... interface {}) (* MessageInfo , error ) {
297+ t := time .Now ().Add (duration )
298+ return q .SendScheduleMsgV2 (payload , t , opts ... )
299+ }
300+
301+ // SendScheduleMsg submits a message delivered at given time
302+ // It is compatible with SendScheduleMsgV2, but does not return MessageInfo
303+ func (q * DelayQueue ) SendScheduleMsg (payload string , t time.Time , opts ... interface {}) error {
304+ _ , err := q .SendScheduleMsgV2 (payload , t , opts ... )
305+ return err
306+ }
307+
308+ // SendDelayMsg submits a message delivered after given duration
309+ // It is compatible with SendDelayMsgV2, but does not return MessageInfo
275310func (q * DelayQueue ) SendDelayMsg (payload string , duration time.Duration , opts ... interface {}) error {
276311 t := time .Now ().Add (duration )
277312 return q .SendScheduleMsg (payload , t , opts ... )
278313}
279314
315+ type InterceptResult struct {
316+ Intercepted bool
317+ State string
318+ }
319+
320+ // TryIntercept trys to intercept a message
321+ func (q * DelayQueue ) TryIntercept (msg * MessageInfo ) (* InterceptResult , error ) {
322+ id := msg .ID ()
323+ // try to intercept at ready
324+ removed , err := q .redisCli .LRem (q .readyKey , 0 , id )
325+ if err != nil {
326+ q .logger .Printf ("intercept %s from ready failed: %v" , id , err )
327+ }
328+ if removed > 0 {
329+ _ = q .redisCli .Del ([]string {q .genMsgKey (id )})
330+ _ = q .redisCli .HDel (q .retryCountKey , []string {id })
331+ return & InterceptResult {
332+ Intercepted : true ,
333+ State : StateReady ,
334+ }, nil
335+ }
336+ // try to intercept at pending
337+ removed , err = q .redisCli .ZRem (q .pendingKey , []string {id })
338+ if err != nil {
339+ q .logger .Printf ("intercept %s from pending failed: %v" , id , err )
340+ }
341+ if removed > 0 {
342+ _ = q .redisCli .Del ([]string {q .genMsgKey (id )})
343+ _ = q .redisCli .HDel (q .retryCountKey , []string {id })
344+ return & InterceptResult {
345+ Intercepted : true ,
346+ State : StatePending ,
347+ }, nil
348+ }
349+ // message may be being consumed or has been successfully consumed
350+ // if the message has been successfully consumed, the following action will cause nothing
351+ // if the message is being consumed,the following action will prevent it from being retried
352+ q .redisCli .HDel (q .retryCountKey , []string {id })
353+ q .redisCli .LRem (q .retryKey , 0 , id )
354+
355+ return & InterceptResult {
356+ Intercepted : false ,
357+ State : StateUnknown ,
358+ }, nil
359+ }
360+
280361func (q * DelayQueue ) loadScript (script string ) (string , error ) {
281362 sha1 , err := q .redisCli .ScriptLoad (script )
282363 if err != nil {
@@ -420,7 +501,7 @@ func (q *DelayQueue) callback(idStr string) error {
420501
421502func (q * DelayQueue ) ack (idStr string ) error {
422503 atomic .AddInt32 (& q .fetchCount , - 1 )
423- err := q .redisCli .ZRem (q .unAckKey , []string {idStr })
504+ _ , err := q .redisCli .ZRem (q .unAckKey , []string {idStr })
424505 if err != nil {
425506 return fmt .Errorf ("remove from unack failed: %v" , err )
426507 }
0 commit comments