dpepbjp126917 2019-09-03 15:25
浏览 1063

Redis Golang客户端会定期丢弃不良的PubSub连接(EOF)

What I did:

I'm using the golang Redis library from github.com/go-redis/redis. My client listens on a PubSub channel called 'control'. Whenever a message arrives, I handle it and continue receiving the next message. I listen endlessly and the messages can come often, or sometimes not for days.

What I expect:

I expect the redis channel to stay open endlessly and receive messages as they are sent.

What I experience:

Usually it runs well for days, but every once in a while client.Receive() returns EOF error. After this error, the client no longer receives messages on that channel. Internally, the redis client prints to stdout the following message:

redis: 2019/08/29 14:18:57 pubsub.go:151: redis: discarding bad PubSub connection: EOF

Disclaimer: I am not certain that this error is what causes me to stop receiving messages, it just seems related.

Additional questions:

I'd like to understand why this happens, if this is normal and if reconnecting to the channel via client.Subscribe() whenever I encounter the behaviour is a good remedy, or should I address the root issue, whatever it may be.

The code:

Here is the entire code that handles my client (connect to redis, subscribe to channel, endlessly receive messages):

func InitAndListenAsync(log *log.Logger, sseHandler func(string, string) error) error {
    rootLogger = log.With(zap.String("component", "redis-client"))

    host := env.RedisHost
    port := env.RedisPort
    pass := env.RedisPass
    addr := fmt.Sprintf("%s:%s", host, port)
    tlsCfg := &tls.Config{}
    client = redis.NewClient(&redis.Options{
        Addr:      addr,
        Password:  pass,
        TLSConfig: tlsCfg,
    })

    if _, err := client.Ping().Result(); err != nil {
        return err
    }

    go func() {
        controlSub := client.Subscribe("control")
        defer controlSub.Close()
        for {
            in, err := controlSub.Receive()  // *** SOMETIMES RETURNS EOF ERROR ***
            if err != nil {
                rootLogger.Error("failed to get feedback", zap.Error(err))
                break
            }
            switch in.(type) {
            case *redis.Message:
                cm := comm.ControlMessageEvent{}
                payload := []byte(in.(*redis.Message).Payload)
                if err := json.Unmarshal(payload, &cm); err != nil {
                    rootLogger.Error("failed to parse control message", zap.Error(err))
                } else if err := handleIncomingEvent(&cm); err != nil {
                    rootLogger.Error("failed to handle control message", zap.Error(err))
                }

            default:
                rootLogger.Warn("Received unknown input over REDIS PubSub control channel", zap.Any("received", in))
            }
        }
    }()
    return nil
}
  • 写回答

1条回答 默认 最新

  • dongyinglan8707 2019-09-03 16:42
    关注

    My take on that is that Redis may disconnect your client if it thinks the client is idling.

    A way to cope with this seems to be like that:

    1. Use ReceiveTimeout rather than Receive.
    2. If the operation timed out, issue Ping and wait for reply.
    3. Rinse, repeat.

    That way, you'll be sure there exists some traffic on the connection—no matter whether there is any data actually published or not.

    I'd start here.

    评论

报告相同问题?

悬赏问题

  • ¥15 想问一下树莓派接上显示屏后出现如图所示画面,是什么问题导致的
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)
  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号