douna2917 2015-08-31 16:19
浏览 264
已采纳

Golang Redis PubSub超时

So far I've been doing this:

import (
    _redis "gopkg.in/redis.v3"
    "strconv"
    "time"
)

type Redis struct {
    Connector   *_redis.Client
    PubSub      *_redis.PubSub
}

var redis *Redis = nil

func NewRedis() bool {
    if redis == nil {
        redis = new(Redis)
        redis.Connector = _redis.NewClient(&_redis.Options{
            Addr: config.RedisHostname + ":" + strconv.FormatInt(config.RedisPort, 10),
            Password: "",
            DB: 0,
        })
        Logger.Log(nil, "Connected to Redis")
        err := redis.Init()
        if err != nil {
            Logger.Fatal(nil, "Cannot setup Redis:", err.Error())
            return false
        }
        return true
    }
    return false
}

func (this *Redis) Init() error {
    pubsub, err := this.Connector.Subscribe("test")
    if err != nil {
        return err
    }
    defer pubsub.Close()
    this.PubSub = pubsub
    for {
        msgi, err := this.PubSub.ReceiveTimeout(100 * time.Millisecond)
        if err != nil {
            Logger.Error(nil, "PubSub error:", err.Error())
            err = this.PubSub.Ping("")
            if err != nil {
                Logger.Error(nil, "PubSub failure:", err.Error())
                break
            }
            continue
        }
        switch msg := msgi.(type) {
            case *_redis.Message:
                Logger.Log(nil, "Received", msg.Payload, "on channel", msg.Channel)
        }
    }
    return nil
}

My Connector is a redis.Client, it's working because I was able to publish messages as well.

When I run my program, I get the following error: PubSub error: WSARecv tcp 127.0.0.1:64505: i/o timeout

Do you have any idea of what I'm doing wrong ? I'm using this package: https://github.com/go-redis/redis

  • 写回答

1条回答 默认 最新

  • dpmir1988 2015-08-31 20:03
    关注

    Some things to note:

    • (implementation detail) When redis goes into PubSub mode, the only thing that happens on that socket afterwards is PubSub events, which is why PubSub in go-redis is abstracted into its own type
    • A PubSub client can potentially subscribe to multiple topics in a single subscriber, hence why there are subscribe/unsubscribe events throughout.
    • the interface has both Receive() and ReceiveTimeout(duration) methods, both of which return the next event on the wire; which can be subscribe/unsubscribe events and message events; (you don't necessarily know which) the only difference between them that Receive blocks forever until there's a new message, and ReceiveTimeout will error on timeout.

    With that in mind, unless you have messages far more than 10/second consistently (in other words, <100 milliseconds between messages), it's inefficient to use that short of a timeout; and I'd argue that due to golang having goroutines, you should almost never use ReceiveTimeout for real applications, or use a sufficiently long timeout like a minute.

    with that in mind, your receive loop should look like:

        for {
            msgi, err := this.PubSub.Receive()
            if err != nil {
                Logger.Error(nil, "PubSub error:", err.Error())
                return err
            }
            switch msg := msgi.(type) {
                case *_redis.Message:
                    Logger.Log(nil, "Received", msg.Payload, "on channel", msg.Channel)
                default:
                    Logger.Log(nil, "Got control message", msg)
            }
        }
    

    If your application really warranted using a timeout, then you should use a type assertion to assert the *net.OpError that signifies a timeout and distinguish it from other more serious errors.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 chaquopy python 安卓
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 CSS实现渐隐虚线框
  • ¥15 有没有帮写代码做实验仿真的
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥30 vmware exsi重置后登不上
  • ¥15 易盾点选的cb参数怎么解啊
  • ¥15 MATLAB运行显示错误,如何解决?
  • ¥15 c++头文件不能识别CDialog
  • ¥15 Excel发现不可读取的内容