2020-01-07 11:23:09 +00:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package queue
import (
2021-02-10 22:28:32 +01:00
"context"
"code.gitea.io/gitea/modules/graceful"
2020-01-07 11:23:09 +00:00
"code.gitea.io/gitea/modules/log"
2020-09-27 22:09:46 +01:00
"code.gitea.io/gitea/modules/nosql"
2020-01-07 11:23:09 +00:00
2021-02-10 22:28:32 +01:00
"github.com/go-redis/redis/v8"
2020-01-07 11:23:09 +00:00
)
// RedisQueueType is the type for redis queue
const RedisQueueType Type = "redis"
2020-02-02 23:19:58 +00:00
// RedisQueueConfiguration is the configuration for the redis queue
type RedisQueueConfiguration struct {
ByteFIFOQueueConfiguration
RedisByteFIFOConfiguration
}
// RedisQueue redis queue
type RedisQueue struct {
* ByteFIFOQueue
}
// NewRedisQueue creates single redis or cluster redis queue
func NewRedisQueue ( handle HandlerFunc , cfg , exemplar interface { } ) ( Queue , error ) {
configInterface , err := toConfig ( RedisQueueConfiguration { } , cfg )
if err != nil {
return nil , err
}
config := configInterface . ( RedisQueueConfiguration )
byteFIFO , err := NewRedisByteFIFO ( config . RedisByteFIFOConfiguration )
if err != nil {
return nil , err
}
byteFIFOQueue , err := NewByteFIFOQueue ( RedisQueueType , byteFIFO , handle , config . ByteFIFOQueueConfiguration , exemplar )
if err != nil {
return nil , err
}
queue := & RedisQueue {
ByteFIFOQueue : byteFIFOQueue ,
}
queue . qid = GetManager ( ) . Add ( queue , RedisQueueType , config , exemplar )
return queue , nil
}
2020-01-07 11:23:09 +00:00
type redisClient interface {
2021-02-10 22:28:32 +01:00
RPush ( ctx context . Context , key string , args ... interface { } ) * redis . IntCmd
2022-01-22 21:22:14 +00:00
LPush ( ctx context . Context , key string , args ... interface { } ) * redis . IntCmd
2021-02-10 22:28:32 +01:00
LPop ( ctx context . Context , key string ) * redis . StringCmd
LLen ( ctx context . Context , key string ) * redis . IntCmd
SAdd ( ctx context . Context , key string , members ... interface { } ) * redis . IntCmd
SRem ( ctx context . Context , key string , members ... interface { } ) * redis . IntCmd
SIsMember ( ctx context . Context , key string , member interface { } ) * redis . BoolCmd
Ping ( ctx context . Context ) * redis . StatusCmd
2020-01-07 11:23:09 +00:00
Close ( ) error
}
2021-04-09 09:40:34 +02:00
var _ ByteFIFO = & RedisByteFIFO { }
2020-02-02 23:19:58 +00:00
// RedisByteFIFO represents a ByteFIFO formed from a redisClient
type RedisByteFIFO struct {
2021-05-15 15:22:26 +01:00
client redisClient
2020-02-02 23:19:58 +00:00
queueName string
2020-01-07 11:23:09 +00:00
}
2020-02-02 23:19:58 +00:00
// RedisByteFIFOConfiguration is the configuration for the RedisByteFIFO
type RedisByteFIFOConfiguration struct {
2020-09-27 22:09:46 +01:00
ConnectionString string
QueueName string
2020-01-07 11:23:09 +00:00
}
2020-02-02 23:19:58 +00:00
// NewRedisByteFIFO creates a ByteFIFO formed from a redisClient
func NewRedisByteFIFO ( config RedisByteFIFOConfiguration ) ( * RedisByteFIFO , error ) {
fifo := & RedisByteFIFO {
queueName : config . QueueName ,
2020-01-07 11:23:09 +00:00
}
2020-09-27 22:09:46 +01:00
fifo . client = nosql . GetManager ( ) . GetRedisClient ( config . ConnectionString )
2021-02-10 22:28:32 +01:00
if err := fifo . client . Ping ( graceful . GetManager ( ) . ShutdownContext ( ) ) . Err ( ) ; err != nil {
2020-01-07 11:23:09 +00:00
return nil , err
}
2020-02-02 23:19:58 +00:00
return fifo , nil
2020-01-07 11:23:09 +00:00
}
2020-02-02 23:19:58 +00:00
// PushFunc pushes data to the end of the fifo and calls the callback if it is added
2021-05-15 15:22:26 +01:00
func ( fifo * RedisByteFIFO ) PushFunc ( ctx context . Context , data [ ] byte , fn func ( ) error ) error {
2020-02-02 23:19:58 +00:00
if fn != nil {
if err := fn ( ) ; err != nil {
return err
2020-01-07 11:23:09 +00:00
}
}
2021-05-15 15:22:26 +01:00
return fifo . client . RPush ( ctx , fifo . queueName , data ) . Err ( )
2020-01-07 11:23:09 +00:00
}
2022-01-22 21:22:14 +00:00
// PushBack pushes data to the top of the fifo
func ( fifo * RedisByteFIFO ) PushBack ( ctx context . Context , data [ ] byte ) error {
return fifo . client . LPush ( ctx , fifo . queueName , data ) . Err ( )
}
2020-02-02 23:19:58 +00:00
// Pop pops data from the start of the fifo
2021-05-15 15:22:26 +01:00
func ( fifo * RedisByteFIFO ) Pop ( ctx context . Context ) ( [ ] byte , error ) {
data , err := fifo . client . LPop ( ctx , fifo . queueName ) . Bytes ( )
2020-02-12 18:12:27 +08:00
if err == nil || err == redis . Nil {
2020-02-02 23:19:58 +00:00
return data , nil
2020-01-29 01:01:06 +00:00
}
2020-02-02 23:19:58 +00:00
return data , err
2020-01-29 01:01:06 +00:00
}
2020-02-02 23:19:58 +00:00
// Close this fifo
func ( fifo * RedisByteFIFO ) Close ( ) error {
return fifo . client . Close ( )
2020-01-07 11:23:09 +00:00
}
2020-02-02 23:19:58 +00:00
// Len returns the length of the fifo
2021-05-15 15:22:26 +01:00
func ( fifo * RedisByteFIFO ) Len ( ctx context . Context ) int64 {
val , err := fifo . client . LLen ( ctx , fifo . queueName ) . Result ( )
2020-02-02 23:19:58 +00:00
if err != nil {
log . Error ( "Error whilst getting length of redis queue %s: Error: %v" , fifo . queueName , err )
return - 1
2020-01-07 11:23:09 +00:00
}
2020-02-02 23:19:58 +00:00
return val
2020-01-07 11:23:09 +00:00
}
func init ( ) {
queuesMap [ RedisQueueType ] = NewRedisQueue
}