132 lines
2.6 KiB
Go
132 lines
2.6 KiB
Go
|
|
package redisUtil
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/gomodule/redigo/redis"
|
||
|
|
)
|
||
|
|
|
||
|
|
// 订阅回调函数
|
||
|
|
type SubscribeCallback func() error
|
||
|
|
|
||
|
|
// Subscriber
|
||
|
|
// @description: 订阅者
|
||
|
|
type Subscriber struct {
|
||
|
|
// pool 订阅者连接池
|
||
|
|
pool *RedisPool
|
||
|
|
// callBack 订阅者回调函数
|
||
|
|
callBack SubscribeCallback
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewSubscriber
|
||
|
|
// @description: 构建一个订阅者
|
||
|
|
// parameter:
|
||
|
|
// @pool:
|
||
|
|
// @callBack:
|
||
|
|
// return:
|
||
|
|
// @*Subscriber:
|
||
|
|
func NewSubscriber(pool *RedisPool, callBack SubscribeCallback) *Subscriber {
|
||
|
|
return &Subscriber{pool: pool, callBack: callBack}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Promulgator
|
||
|
|
// @description: 发布者
|
||
|
|
type Promulgator struct {
|
||
|
|
// pool 发布者连接池
|
||
|
|
pool *RedisPool
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewPromulgator
|
||
|
|
// @description: 构建一个发布者
|
||
|
|
// parameter:
|
||
|
|
// @pool:
|
||
|
|
// return:
|
||
|
|
// @*Promulgator:
|
||
|
|
func NewPromulgator(pool *RedisPool) *Promulgator {
|
||
|
|
return &Promulgator{pool: pool}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Publish
|
||
|
|
// @description: 发布消息
|
||
|
|
// parameter:
|
||
|
|
// @receiver s:
|
||
|
|
// @channel:
|
||
|
|
// @message:
|
||
|
|
// return:
|
||
|
|
// @error:
|
||
|
|
func (s *Promulgator) Publish(channel, message string) error {
|
||
|
|
c := s.pool.GetConnection()
|
||
|
|
defer c.Close()
|
||
|
|
|
||
|
|
_, err := c.Do("PUBLISH", channel, message)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("redis publish %s %s, err: %v", channel, message, err)
|
||
|
|
}
|
||
|
|
//n, err := s.pool.Int(result)
|
||
|
|
//if err != nil {
|
||
|
|
// return fmt.Errorf("redis publish %s %s, err: %v", channel, message, err)
|
||
|
|
//}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Subscribe
|
||
|
|
// @description: 订阅者订阅消息
|
||
|
|
// parameter:
|
||
|
|
// @receiver s:
|
||
|
|
// @ctx:
|
||
|
|
// @channel: 频道
|
||
|
|
// return:
|
||
|
|
// @error:
|
||
|
|
func (s *Subscriber) Subscribe(ctx context.Context, channel ...string) error {
|
||
|
|
sub := redis.PubSubConn{Conn: s.pool.GetConnection()}
|
||
|
|
if err := sub.Subscribe(redis.Args{}.AddFlat(channel)...); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
done := make(chan error, 1)
|
||
|
|
|
||
|
|
// 启动一个新协程去持续订阅消息
|
||
|
|
go func() {
|
||
|
|
defer sub.Close()
|
||
|
|
for {
|
||
|
|
switch msg := sub.Receive().(type) {
|
||
|
|
case error:
|
||
|
|
done <- fmt.Errorf("redis pubsub receive err: %v", msg)
|
||
|
|
return
|
||
|
|
case redis.Message:
|
||
|
|
if err := s.callBack(); err != nil {
|
||
|
|
done <- err
|
||
|
|
return
|
||
|
|
}
|
||
|
|
case redis.Subscription:
|
||
|
|
if msg.Count == 0 {
|
||
|
|
// 所有的订阅者都退出
|
||
|
|
done <- nil
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}()
|
||
|
|
|
||
|
|
// health check
|
||
|
|
tick := time.NewTicker(time.Minute)
|
||
|
|
defer tick.Stop()
|
||
|
|
for {
|
||
|
|
select {
|
||
|
|
case <-ctx.Done():
|
||
|
|
if err := sub.Unsubscribe(); err != nil {
|
||
|
|
return fmt.Errorf("redis pubsub unsubscribe err: %v", err)
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
case err := <-done:
|
||
|
|
return err
|
||
|
|
case <-tick.C:
|
||
|
|
if err := sub.Ping(""); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|