code.gitea.io/gitea@v1.19.3/modules/queue/unique_queue_redis.go (about) 1 // Copyright 2019 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package queue 5 6 import ( 7 "context" 8 9 "github.com/redis/go-redis/v9" 10 ) 11 12 // RedisUniqueQueueType is the type for redis queue 13 const RedisUniqueQueueType Type = "unique-redis" 14 15 // RedisUniqueQueue redis queue 16 type RedisUniqueQueue struct { 17 *ByteFIFOUniqueQueue 18 } 19 20 // RedisUniqueQueueConfiguration is the configuration for the redis queue 21 type RedisUniqueQueueConfiguration struct { 22 ByteFIFOQueueConfiguration 23 RedisUniqueByteFIFOConfiguration 24 } 25 26 // NewRedisUniqueQueue creates single redis or cluster redis queue. 27 // 28 // Please note that this Queue does not guarantee that a particular 29 // task cannot be processed twice or more at the same time. Uniqueness is 30 // only guaranteed whilst the task is waiting in the queue. 31 func NewRedisUniqueQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error) { 32 configInterface, err := toConfig(RedisUniqueQueueConfiguration{}, cfg) 33 if err != nil { 34 return nil, err 35 } 36 config := configInterface.(RedisUniqueQueueConfiguration) 37 38 byteFIFO, err := NewRedisUniqueByteFIFO(config.RedisUniqueByteFIFOConfiguration) 39 if err != nil { 40 return nil, err 41 } 42 43 if len(byteFIFO.setName) == 0 { 44 byteFIFO.setName = byteFIFO.queueName + "_unique" 45 } 46 47 byteFIFOQueue, err := NewByteFIFOUniqueQueue(RedisUniqueQueueType, byteFIFO, handle, config.ByteFIFOQueueConfiguration, exemplar) 48 if err != nil { 49 return nil, err 50 } 51 52 queue := &RedisUniqueQueue{ 53 ByteFIFOUniqueQueue: byteFIFOQueue, 54 } 55 56 queue.qid = GetManager().Add(queue, RedisUniqueQueueType, config, exemplar) 57 58 return queue, nil 59 } 60 61 var _ UniqueByteFIFO = &RedisUniqueByteFIFO{} 62 63 // RedisUniqueByteFIFO represents a UniqueByteFIFO formed from a redisClient 64 type RedisUniqueByteFIFO struct { 65 RedisByteFIFO 66 setName string 67 } 68 69 // RedisUniqueByteFIFOConfiguration is the configuration for the RedisUniqueByteFIFO 70 type RedisUniqueByteFIFOConfiguration struct { 71 RedisByteFIFOConfiguration 72 SetName string 73 } 74 75 // NewRedisUniqueByteFIFO creates a UniqueByteFIFO formed from a redisClient 76 func NewRedisUniqueByteFIFO(config RedisUniqueByteFIFOConfiguration) (*RedisUniqueByteFIFO, error) { 77 internal, err := NewRedisByteFIFO(config.RedisByteFIFOConfiguration) 78 if err != nil { 79 return nil, err 80 } 81 82 fifo := &RedisUniqueByteFIFO{ 83 RedisByteFIFO: *internal, 84 setName: config.SetName, 85 } 86 87 return fifo, nil 88 } 89 90 // PushFunc pushes data to the end of the fifo and calls the callback if it is added 91 func (fifo *RedisUniqueByteFIFO) PushFunc(ctx context.Context, data []byte, fn func() error) error { 92 added, err := fifo.client.SAdd(ctx, fifo.setName, data).Result() 93 if err != nil { 94 return err 95 } 96 if added == 0 { 97 return ErrAlreadyInQueue 98 } 99 if fn != nil { 100 if err := fn(); err != nil { 101 return err 102 } 103 } 104 return fifo.client.RPush(ctx, fifo.queueName, data).Err() 105 } 106 107 // PushBack pushes data to the top of the fifo 108 func (fifo *RedisUniqueByteFIFO) PushBack(ctx context.Context, data []byte) error { 109 added, err := fifo.client.SAdd(ctx, fifo.setName, data).Result() 110 if err != nil { 111 return err 112 } 113 if added == 0 { 114 return ErrAlreadyInQueue 115 } 116 return fifo.client.LPush(ctx, fifo.queueName, data).Err() 117 } 118 119 // Pop pops data from the start of the fifo 120 func (fifo *RedisUniqueByteFIFO) Pop(ctx context.Context) ([]byte, error) { 121 data, err := fifo.client.LPop(ctx, fifo.queueName).Bytes() 122 if err != nil && err != redis.Nil { 123 return data, err 124 } 125 126 if len(data) == 0 { 127 return data, nil 128 } 129 130 err = fifo.client.SRem(ctx, fifo.setName, data).Err() 131 return data, err 132 } 133 134 // Has returns whether the fifo contains this data 135 func (fifo *RedisUniqueByteFIFO) Has(ctx context.Context, data []byte) (bool, error) { 136 return fifo.client.SIsMember(ctx, fifo.setName, data).Result() 137 } 138 139 func init() { 140 queuesMap[RedisUniqueQueueType] = NewRedisUniqueQueue 141 }