code.gitea.io/gitea@v1.19.3/modules/queue/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 "code.gitea.io/gitea/modules/graceful" 10 "code.gitea.io/gitea/modules/log" 11 "code.gitea.io/gitea/modules/nosql" 12 13 "github.com/redis/go-redis/v9" 14 ) 15 16 // RedisQueueType is the type for redis queue 17 const RedisQueueType Type = "redis" 18 19 // RedisQueueConfiguration is the configuration for the redis queue 20 type RedisQueueConfiguration struct { 21 ByteFIFOQueueConfiguration 22 RedisByteFIFOConfiguration 23 } 24 25 // RedisQueue redis queue 26 type RedisQueue struct { 27 *ByteFIFOQueue 28 } 29 30 // NewRedisQueue creates single redis or cluster redis queue 31 func NewRedisQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error) { 32 configInterface, err := toConfig(RedisQueueConfiguration{}, cfg) 33 if err != nil { 34 return nil, err 35 } 36 config := configInterface.(RedisQueueConfiguration) 37 38 byteFIFO, err := NewRedisByteFIFO(config.RedisByteFIFOConfiguration) 39 if err != nil { 40 return nil, err 41 } 42 43 byteFIFOQueue, err := NewByteFIFOQueue(RedisQueueType, byteFIFO, handle, config.ByteFIFOQueueConfiguration, exemplar) 44 if err != nil { 45 return nil, err 46 } 47 48 queue := &RedisQueue{ 49 ByteFIFOQueue: byteFIFOQueue, 50 } 51 52 queue.qid = GetManager().Add(queue, RedisQueueType, config, exemplar) 53 54 return queue, nil 55 } 56 57 type redisClient interface { 58 RPush(ctx context.Context, key string, args ...interface{}) *redis.IntCmd 59 LPush(ctx context.Context, key string, args ...interface{}) *redis.IntCmd 60 LPop(ctx context.Context, key string) *redis.StringCmd 61 LLen(ctx context.Context, key string) *redis.IntCmd 62 SAdd(ctx context.Context, key string, members ...interface{}) *redis.IntCmd 63 SRem(ctx context.Context, key string, members ...interface{}) *redis.IntCmd 64 SIsMember(ctx context.Context, key string, member interface{}) *redis.BoolCmd 65 Ping(ctx context.Context) *redis.StatusCmd 66 Close() error 67 } 68 69 var _ ByteFIFO = &RedisByteFIFO{} 70 71 // RedisByteFIFO represents a ByteFIFO formed from a redisClient 72 type RedisByteFIFO struct { 73 client redisClient 74 75 queueName string 76 } 77 78 // RedisByteFIFOConfiguration is the configuration for the RedisByteFIFO 79 type RedisByteFIFOConfiguration struct { 80 ConnectionString string 81 QueueName string 82 } 83 84 // NewRedisByteFIFO creates a ByteFIFO formed from a redisClient 85 func NewRedisByteFIFO(config RedisByteFIFOConfiguration) (*RedisByteFIFO, error) { 86 fifo := &RedisByteFIFO{ 87 queueName: config.QueueName, 88 } 89 fifo.client = nosql.GetManager().GetRedisClient(config.ConnectionString) 90 if err := fifo.client.Ping(graceful.GetManager().ShutdownContext()).Err(); err != nil { 91 return nil, err 92 } 93 return fifo, nil 94 } 95 96 // PushFunc pushes data to the end of the fifo and calls the callback if it is added 97 func (fifo *RedisByteFIFO) PushFunc(ctx context.Context, data []byte, fn func() error) error { 98 if fn != nil { 99 if err := fn(); err != nil { 100 return err 101 } 102 } 103 return fifo.client.RPush(ctx, fifo.queueName, data).Err() 104 } 105 106 // PushBack pushes data to the top of the fifo 107 func (fifo *RedisByteFIFO) PushBack(ctx context.Context, data []byte) error { 108 return fifo.client.LPush(ctx, fifo.queueName, data).Err() 109 } 110 111 // Pop pops data from the start of the fifo 112 func (fifo *RedisByteFIFO) Pop(ctx context.Context) ([]byte, error) { 113 data, err := fifo.client.LPop(ctx, fifo.queueName).Bytes() 114 if err == nil || err == redis.Nil { 115 return data, nil 116 } 117 return data, err 118 } 119 120 // Close this fifo 121 func (fifo *RedisByteFIFO) Close() error { 122 return fifo.client.Close() 123 } 124 125 // Len returns the length of the fifo 126 func (fifo *RedisByteFIFO) Len(ctx context.Context) int64 { 127 val, err := fifo.client.LLen(ctx, fifo.queueName).Result() 128 if err != nil { 129 log.Error("Error whilst getting length of redis queue %s: Error: %v", fifo.queueName, err) 130 return -1 131 } 132 return val 133 } 134 135 func init() { 136 queuesMap[RedisQueueType] = NewRedisQueue 137 }