red

package module
v0.0.0-...-0fa6226 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 16, 2024 License: Apache-2.0 Imports: 11 Imported by: 4

README


goclub/redis

Go Reference

易用性

go 社区有很多 redis 库, 但是大多数库在 redis 返回 nil 时候用 error 表示.例如使用GET方法:

cmd := client.Get(ctx, "name")
err = cmd.Err()
isNil := false
if err != nil {
    if errors.Is(err, redis.Nil) {
        isNil = true
    } else {
        return err
    }
}
if isNil {
    // do some
} else {
    log.Print(cmd.String())
}

代码写的复杂,心很累.

goclub/redis 的接口风格是

value, isNil, err := red.GET{Key:key}.Do(ctx, client) ; if err != nil {
    return
}
if isNil {
	// do some
} else {
	log.Print(value)
}

自由

redis 的核心是 RESP 协议. goclub/redis 提供以下接口对应 RESP.

// Connecter RESP
type Connecter interface {
	DoStringReply(ctx context.Context, args []string) (reply string, isNil bool, err error)
	DoStringReplyWithoutNil(ctx context.Context, args []string) (reply string, err error)
	DoIntegerReply(ctx context.Context, args []string) (reply int64, isNil bool, err error)
	DoIntegerReplyWithoutNil(ctx context.Context, args []string) (reply int64, err error)
	DoArrayIntegerReply(ctx context.Context, args []string) (reply []OptionInt64, err error)
	DoArrayStringReply(ctx context.Context, args []string) (reply []OptionString, err error)
	Eval(ctx context.Context, script Script) (reply Reply, isNil bool, err error)
	EvalWithoutNil(ctx context.Context, script Script) (reply Reply, err error)
}

你可以自由的使用任何命令.

replyInt64, err = client.DoIntegerReplyWithoutNil(
	ctx, 
	[]string{
		"HSET", key, "name", "goclub", "age", "18",
	})
if err != nil {
    return
}

你也可以查看 red.API 查看 goclub/redis 对哪些方法进行了封装


像是 RESP Simple Strings 这类操作你可以根据 redis 是否会返回 nil 去调用 DoStringReplyDoStringReplyWithoutNil

脚本则使用 Eval 或者EvalWithoutNil

script := `
if redis.call("GET", KEYS[1]) == ARGV[1]
then
	return redis.call("DEL", KEYS[1])
else
	return 0
end
`
reply, err := client.EvalWithoutNil(ctx, Script{
    KEYS: []string{key},
    ARGV: []string{value},
    Script: script,
}) ; if err != nil {
    return
}
/*
你可以根据 script 内容调用一下 reply 方法
reply.Int64()
reply.Uint64()
reply.String()
reply.Int64Slice()
reply.StringSlice()
*/

包容

你可以将 goclub/redis 理解为是一个驱动库,是一个"壳". goclub/redis 能通过接口适配 go 社区的说有 redis 库.

goredis 是非常流行的库, goclub/redis 默认支持了 goredisv8

直接来吧

连接redis | NewClient

字符串增删改查 | StringsCRUD

eval执行脚本 | Eval

直接写命令 |l DoIntegerReply

实用方法

goclub/redis 还基于redis实现了了一些实用的方法,帮助开发人员提高开发效率.防止重复造轮子.

Trigger

触发器

// Trigger 触发器
// 每5分钟出现3次则触发,但是10分钟内只触发一次
func exmaple () {
	triggered, err := red.Trigger{
		Namespace: "pay_fail_alarm",
		Interval: time.Minute*5,
		Threshold: 3,
		Frequency: time.Minute*5,
	}.Do(ctx, client) ; if err != nil {
	    return
	}
	if triggered {
		// do some
	}
}

Mutex

互斥锁

mutex := red.Mutex{
    Key: key,
	// Expire 控制锁定时间
    Expire: time.Millisecond*100,
	// Retry 当锁被占用时进入循环重试(此时会堵塞)
	// Retry.Times 重试上锁多少次
	// Retry.Interval 重试上锁间隔
    Retry: red.Retry{
        Times: 3,
		Interval:time.Millisecond*100,
    },
}
lockSuccess, unlock, err := mutex.Lock(context.TODO(), client) ; if err != nil {
    // 锁失败
    return
}
if lockSuccess == false {
    // 锁被占用
    return
}
// 处理某些业务
err = unlock(context.TODO()) ; if err != nil {
    *mutexCount--
	// 解锁失败
	log.Printf("%+v", err)
    return
}
// 解锁成功

IncrLimiter

递增限制器

alarm_1 := IncrLimiter{
    Namespace: "incr_limiter_alarm_1",
    Expire:    time.Second * 10,
    Maximum:   3,
}
/* 第1次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第2次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第3次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第4次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
    return
} // limited = true

SetLimiter

设值限制器

使用场景: 限制用户每天只能试读3个章节(如果不允许一天内反复试读相同章节则可以使用 IncrLimiter )
注意:
如果 Key = free_trial:{userID} Expire = 24h 是限制24小时
如果 Key = free_trial:2022-01-01:{userID} Expire = 24h 是限制每天

/* 第1次 用户1访问了章节1 */
limited, err := SetLimiter{
    Key:       "free_trial:2022-05-25:userID:1",
    Member:    "1"
    Expire:    time.Hour * 24,
    Maximum:   3,
}.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第2次 用户1重复访问了章节1 */
limited, err := SetLimiter{
    Key:       "free_trial:2022-05-25:userID:1",
    Member:    "1"
    Expire:    time.Hour * 24,
    Maximum:   3,
}.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第3次 用户1访问了章节2 */
limited, err := SetLimiter{
    Key:       "free_trial:2022-05-25:userID:1",
    Member:    "2"
    Expire:    time.Hour * 24,
    Maximum:   3,
}.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第4次 用户1访问了章节3 */
limited, err := SetLimiter{
    Key:       "free_trial:2022-05-25:userID:1",
    Member:    "3"
    Expire:    time.Hour * 24,
    Maximum:   3,
}.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第5次 用户1访问了章节4 */
limited, err := SetLimiter{
    Key:       "free_trial:2022-05-25:userID:1",
    Member:    "4"
    Expire:    time.Hour * 24,
    Maximum:   3,
}.Do(ctx, client) ; if err != nil {
    return
} // limited = true

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrSetForgetTimeToLive = errors.New("goclub/redis: SET maybe you forget set field Expire or ExpireAt or KeepTTL or NeverExpire")

Functions

func ArgsToInterfaces

func ArgsToInterfaces(args []string) (interfaces []interface{})

func MakeKey

func MakeKey(elems ...string) (key string)

MakeKey MakeKey("user", today, "count") // "user:2022-01-01:count"

Types

type API

type API struct {
	// strings
	Append   APPEND
	BitCount BITCOUNT
	BitField BITFIELD
	BitOp    BITOP
	BitPos   BITPOS
	Decr     DECR
	DecrBy   DECRBY
	Get      GET
	GetBit   GETBIT
	GetDel   GETDEL
	GetEx    GETEX
	GetRange GETRANGE
	// GETSET: Please use SET (GETSET有清空TTL的"隐患")
	Incr        INCR
	IncrBy      INCRBY
	IncrByFloat INCRBYFLOAT
	MGet        MGET
	MSet        MSET
	MSetNX      MSETNX
	// PSETEX: Please use SET
	Set      SET
	SetBit   SETBIT
	SetRange SETRANGE
	// STRALGO TODO
	StrLen STRLEN

	// keys
	Copy       COPY
	Del        DEL
	Unlink     UNLINK
	Dump       DUMP
	Exists     EXISTS
	Expire     EXPIRE
	ExpireAt   EXPIREAT   // @needtest
	ExpireTime EXPIRETIME // @needtest
	Keys       KEYS
	PExpire    PEXPIRE
	// PEXPIREAT
	// PEXPIRETIME
	PTTL PTTL
	// RENAME
	// RENAMENX
	// RESTORE
	// SORT
	// SORT_RO
	// TOUCH
	// TTL
	// TYPE
	// UNLINK
	// WAIT
	// SCAN
	HDEL HDEL
}

type APPEND

type APPEND struct {
	Key   string
	Value string
}

func (APPEND) Do

func (data APPEND) Do(ctx context.Context, client Connecter) (length uint64, err error)

type BITCOUNT

type BITCOUNT struct {
	Key string
	// start and end offset unit byte (8bit)
	StartByte OptionInt64
	EndByte   OptionInt64
}

func (BITCOUNT) Do

func (data BITCOUNT) Do(ctx context.Context, client Connecter) (length uint64, err error)

type BITFIELD

type BITFIELD struct {
	Key  string
	Args []string
}

func (BITFIELD) Do

func (data BITFIELD) Do(ctx context.Context, client Connecter) (reply []OptionInt64, err error)

type BITOP

type BITOP struct {
	AND     bool
	OR      bool
	XOR     bool
	NOT     bool
	DestKey string
	Key     string
	Keys    []string
}

bit operation

func (BITOP) Do

func (data BITOP) Do(ctx context.Context, client Connecter) (size uint64, err error)

type BITPOS

type BITPOS struct {
	Key   string
	Bit   uint8
	Start OptionUint64
	End   OptionUint64
}

func (BITPOS) Do

func (data BITPOS) Do(ctx context.Context, client Connecter) (position int64, err error)

type COPY

type COPY struct {
	Source      string
	Destination string
	DB          OptionUint8
	Replace     bool
}

func (COPY) Do

func (data COPY) Do(ctx context.Context, client Connecter) (reply int64, err error)

When Source is exists and Destination is inexistence return 1 Otherwise return 0

type Connecter

type Connecter interface {
	DoStringReply(ctx context.Context, args []string) (reply string, isNil bool, err error)
	DoStringReplyWithoutNil(ctx context.Context, args []string) (reply string, err error)
	DoIntegerReply(ctx context.Context, args []string) (reply int64, isNil bool, err error)
	DoIntegerReplyWithoutNil(ctx context.Context, args []string) (reply int64, err error)
	DoArrayIntegerReply(ctx context.Context, args []string) (reply []OptionInt64, err error)
	DoArrayStringReply(ctx context.Context, args []string) (reply []OptionString, err error)
	Eval(ctx context.Context, script Script) (reply Reply, isNil bool, err error)
	EvalWithoutNil(ctx context.Context, script Script) (reply Reply, err error)
}

Connecter RESP

type DECR

type DECR struct {
	Key string
}

func (DECR) Do

func (data DECR) Do(ctx context.Context, client Connecter) (newValue int64, err error)

type DECRBY

type DECRBY struct {
	Key       string
	Decrement int64
}

func (DECRBY) Do

func (data DECRBY) Do(ctx context.Context, client Connecter) (newValue int64, err error)

type DEL

type DEL struct {
	Key  string `note:"DEL If your redis version >= 4.0.0, use UNLINK whenever possible"`
	Keys []string
}

func (DEL) Do

func (data DEL) Do(ctx context.Context, client Connecter) (delTotal uint64, err error)

type DUMP

type DUMP struct {
	Key string
}

func (DUMP) Do

func (data DUMP) Do(ctx context.Context, client Connecter) (value string, err error)

type EXISTS

type EXISTS struct {
	Key  string
	Keys []string
}

func (EXISTS) Do

func (data EXISTS) Do(ctx context.Context, client Connecter) (existsCount uint64, err error)

type EXPIRE

type EXPIRE struct {
	Key      string
	Duration time.Duration
	NX       bool
	XX       bool
	GT       bool
	LT       bool
}

func (EXPIRE) Do

func (data EXPIRE) Do(ctx context.Context, client Connecter) (reply int64, err error)

type EXPIREAT

type EXPIREAT struct {
	Key  string
	Time time.Time
	NX   bool
	XX   bool
	GT   bool
	LT   bool
}

func (EXPIREAT) Do

func (data EXPIREAT) Do(ctx context.Context, client Connecter) (reply int64, err error)

type EXPIRETIME

type EXPIRETIME struct {
	Key string
}

func (EXPIRETIME) Do

func (data EXPIRETIME) Do(ctx context.Context, client Connecter) (reply int64, err error)

type ErrUnlock

type ErrUnlock struct {
	IsTimeout         bool
	IsUnexpectedError bool
	IsConnectErr      bool
	Err               error
}

func AsErrUnlock

func AsErrUnlock(err error) (unlockErr *ErrUnlock, asErrUnlock bool)

func (*ErrUnlock) Error

func (e *ErrUnlock) Error() string

自定义错误的 Error 方法一定要加 (*Errxxx) 原因:https://github.com/goclub/error

func (*ErrUnlock) Unwrap

func (e *ErrUnlock) Unwrap() error

type GET

type GET struct {
	Key string
}

func (GET) Do

func (data GET) Do(ctx context.Context, client Connecter) (value string, isNil bool, err error)

type GETBIT

type GETBIT struct {
	Key    string
	Offset uint64
}

func (GETBIT) Do

func (data GETBIT) Do(ctx context.Context, client Connecter) (value uint8, err error)

type GETDEL

type GETDEL struct {
	Key string
}

func (GETDEL) Do

func (data GETDEL) Do(ctx context.Context, client Connecter) (value string, isNil bool, err error)

type GETEX

type GETEX struct {
	Key      string
	Expire   time.Duration
	ExpireAt time.Time
	PERSIST  bool
}

func (GETEX) Do

func (data GETEX) Do(ctx context.Context, client Connecter) (value string, isNil bool, err error)

type GETRANGE

type GETRANGE struct {
	Key   string
	Start int64
	End   int64
}

func (GETRANGE) Do

func (data GETRANGE) Do(ctx context.Context, client Connecter) (value string, err error)

type GoRedisV8

type GoRedisV8 struct {
	Core redis.UniversalClient
}

func NewGoRedisV8

func NewGoRedisV8(goredisV8Client redis.UniversalClient) GoRedisV8

func (GoRedisV8) DoArrayIntegerReply

func (r GoRedisV8) DoArrayIntegerReply(ctx context.Context, args []string) (reply []OptionInt64, err error)

func (GoRedisV8) DoArrayStringReply

func (r GoRedisV8) DoArrayStringReply(ctx context.Context, args []string) (reply []OptionString, err error)

func (GoRedisV8) DoIntegerReply

func (r GoRedisV8) DoIntegerReply(ctx context.Context, args []string) (reply int64, isNil bool, err error)

func (GoRedisV8) DoIntegerReplyWithoutNil

func (r GoRedisV8) DoIntegerReplyWithoutNil(ctx context.Context, args []string) (reply int64, err error)

func (GoRedisV8) DoStringReply

func (r GoRedisV8) DoStringReply(ctx context.Context, args []string) (reply string, isNil bool, err error)

func (GoRedisV8) DoStringReplyWithoutNil

func (r GoRedisV8) DoStringReplyWithoutNil(ctx context.Context, args []string) (reply string, err error)

func (GoRedisV8) Eval

func (r GoRedisV8) Eval(ctx context.Context, data Script) (reply Reply, isNil bool, err error)

func (GoRedisV8) EvalWithoutNil

func (r GoRedisV8) EvalWithoutNil(ctx context.Context, data Script) (reply Reply, err error)

type HDEL

type HDEL struct {
	Key   string
	Field []string
}

func (HDEL) Do

func (data HDEL) Do(ctx context.Context, client Connecter) (delTotal uint64, err error)

type INCR

type INCR struct {
	Key string
}

func (INCR) Do

func (data INCR) Do(ctx context.Context, client Connecter) (newValue int64, err error)

type INCRBY

type INCRBY struct {
	Key       string
	Increment int64
}

func (INCRBY) Do

func (data INCRBY) Do(ctx context.Context, client Connecter) (newValue int64, err error)

type INCRBYFLOAT

type INCRBYFLOAT struct {
	Key       string
	Increment string `eg:"strconv.FormatFloat(value, 'f', 2, 64)"`
}

func (INCRBYFLOAT) Do

func (data INCRBYFLOAT) Do(ctx context.Context, client Connecter) (newValue float64, err error)

type IncrLimiter

type IncrLimiter struct {
	Key       string        `note:"key" eg:"mq_requeue:{messageID}"`
	Expire    time.Duration `note:"有效期" eg:"time.Minute"`
	Maximum   uint64        `note:"最大限制" eg:"3"`
	Increment uint64        `note:"递增值" default:"1"`
}

IncrLimiter 递增限制器 eg:消息队列:重新入队:消息ID作为key在1分钟内只能递增3次.三次内返回的Limited为false,超过三次为true

func (IncrLimiter) Do

func (v IncrLimiter) Do(ctx context.Context, client Connecter) (limited bool, err error)

type KEYS

type KEYS struct {
	Pattern string
}

func (KEYS) Do

func (data KEYS) Do(ctx context.Context, client Connecter) (keys []string, err error)

type KeyValue

type KeyValue struct {
	Key   string
	Value string
}

type MGET

type MGET struct {
	Keys []string
}

func (MGET) Do

func (data MGET) Do(ctx context.Context, client Connecter) (values []OptionString, err error)

type MSET

type MSET struct {
	KeysValues []KeyValue
}

func (MSET) Do

func (data MSET) Do(ctx context.Context, client Connecter) (err error)

type MSETNX

type MSETNX struct {
	KeysValues []KeyValue
}

func (MSETNX) Do

func (data MSETNX) Do(ctx context.Context, client Connecter) (result int8, err error)

type Mutex

type Mutex struct {
	Key    string
	Expire time.Duration
	Retry  Retry
	// contains filtered or unexported fields
}

func (*Mutex) Lock

func (data *Mutex) Lock(ctx context.Context, client Connecter) (ok bool, unlock func(ctx context.Context) (err error), err error)

type OptionDuration

type OptionDuration struct {
	Valid    bool
	Duration time.Duration
}

func NewOptionDuration

func NewOptionDuration(duration time.Duration) OptionDuration

type OptionInt64

type OptionInt64 struct {
	Valid bool
	Int64 int64
}

func NewOptionInt64

func NewOptionInt64(i int64) OptionInt64

type OptionString

type OptionString struct {
	Valid  bool
	String string
}

func NewOptionString

func NewOptionString(s string) OptionString

type OptionUint32

type OptionUint32 struct {
	Valid  bool
	Uint32 uint32
}

func NewOptionUint32

func NewOptionUint32(i uint32) OptionUint32

type OptionUint64

type OptionUint64 struct {
	Valid  bool
	Uint64 uint64
}

func NewOptionUint64

func NewOptionUint64(i uint64) OptionUint64

type OptionUint8

type OptionUint8 struct {
	Valid bool
	Uint8 uint8
}

func NewOptionUint8

func NewOptionUint8(i uint8) OptionUint8

type PEXPIRE

type PEXPIRE struct {
	Key      string
	Duration time.Duration
	NX       bool
	XX       bool
	GT       bool
	LT       bool
}

func (PEXPIRE) Do

func (data PEXPIRE) Do(ctx context.Context, client Connecter) (reply int64, err error)

type PTTL

type PTTL struct {
	Key string
}

func (PTTL) Do

func (data PTTL) Do(ctx context.Context, client Connecter) (result ResultTTL, err error)

type Reply

type Reply struct {
	Value interface{}
}

func (Reply) Int64

func (r Reply) Int64() (v int64, err error)

func (Reply) Int64Slice

func (r Reply) Int64Slice() (int64Slice []OptionInt64, err error)

func (Reply) String

func (r Reply) String() (s string, err error)

func (Reply) StringSlice

func (r Reply) StringSlice() (stringSlice []OptionString, err error)
func (r Reply) InterfaceSlice() (interfaceSlice []interface{}, err error) {
	switch value := r.Value.(type) {
	case []interface{}:
		return value, nil
	default:
		return nil, fmt.Errorf("redis: unexpected type(%T) value(%+v) convert []interface", value, value)
	}
}

func (Reply) Uint64

func (r Reply) Uint64() (v uint64, err error)

type ResultTTL

type ResultTTL struct {
	TTL             time.Duration
	NeverExpire     bool
	KeyDoesNotExist bool
}

type Retry

type Retry struct {
	Times    uint8
	Interval time.Duration
}

type SET

type SET struct {
	NeverExpire bool
	Key         string
	Value       string
	Expire      time.Duration
	ExpireAt    time.Time // >= 6.2: Added the GET, EXAT and PXAT option. (ExpireAt)
	KeepTTL     bool      // >= 6.0: Added the KEEPTTL option.
	XX          bool
	NX          bool
	GET         bool
}

func (SET) Do

func (data SET) Do(ctx context.Context, client Connecter) (reply string, isNil bool, err error)

type SETBIT

type SETBIT struct {
	Key    string
	Offset uint64
	Value  uint8
}

func (SETBIT) Do

func (data SETBIT) Do(ctx context.Context, client Connecter) (originalValue uint8, err error)

type SETRANGE

type SETRANGE struct {
	Key    string
	Offset int64
	Value  string
}

func (SETRANGE) Do

func (data SETRANGE) Do(ctx context.Context, client Connecter) (length int64, err error)

type STRLEN

type STRLEN struct {
	Key string
}

func (STRLEN) Do

func (data STRLEN) Do(ctx context.Context, client Connecter) (length int64, err error)

type Script

type Script struct {
	KEYS   []string
	ARGV   []string
	Script string
}

type SetLimiter

type SetLimiter struct {
	Key     string        `eg:"free_trial:2022-01-01:{userID}"`
	Member  string        `eg:"{chapterID}"`
	Expire  time.Duration `note:"有效期" eg:"time.Hour*24"`
	Maximum uint64        `note:"最大限制" eg:"3"`
}

SetLimiter 集合限制器 使用场景: 限制用户每天只能试读3个章节(如果不允许一天内反复试读相同章节则可以使用 IncrLimiter )

func (SetLimiter) Do

func (v SetLimiter) Do(ctx context.Context, client Connecter) (limited bool, err error)

type Trigger

type Trigger struct {
	Namespace string        `note:"命名空间" eg:"alarm_login_fail:user:1"`
	Interval  time.Duration `note:"持续多久"`
	Threshold uint64        `note:"累计多少次"`
	Frequency time.Duration `note:"多久最多只触发一次 建议与Interval相同"`
}

Trigger 触发器 每5分钟出现3次则触发,但是10分钟内只触发一次

func exmaple () {
	triggered, err := Trigger{
		Namespace: "pay_fail_alarm",
		Interval: time.Minute*5,
		Threshold: 3,
		Frequency: time.Minute*5,
	}.Do(ctx, client) ; if err != nil {
	    return
	}
	if triggered {
		// do some
	}
}

func (Trigger) Do

func (v Trigger) Do(ctx context.Context, client Connecter) (triggered bool, err error)
type UNLINK struct {
	Key  string
	Keys []string
}

func (UNLINK) Do

func (data UNLINK) Do(ctx context.Context, client Connecter) (unlinkTotal uint64, err error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL