如何确保redis用户在Go(Golang)中接收消息?

时间:2016-12-17 09:30:57

标签: go redis node-redis go-gin

我正在使用gin框架来构建API服务器。总的来说,我建立了2个项目。项目'API'和项目'SOCKET'。项目'API'是将在Android中使用的主要REST API,使用gin框架(golang)开发。 Project 'SOCKET'是将使用socket.js(Socket.IO

的套接字连接的客户端的套接字服务器

这个过程就是这样开始的:
用户A:作为请求者;连接到"API"
用户B:作为响应者; B连接到"SOCKET"

User A从android调用API requestData,请求将由"API"的项目处理。 Project "API"将记录请求,并在redis上发布 使用pubsub作为new_request

这是代码:

client := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "", // no password set
    DB:       0,  // use default DB
})

pong, err := client.Ping().Result()

fmt.Println(pong, err)

 if err !=nil {
    fmt.Println("err",err);
 }


pubsub, err := client.Subscribe("responseclient")
if err !=nil {
    panic(err)
}
defer pubsub.Close()

err = client.Publish("new_request", "Example New Request").Err()

if err !=nil {
    panic(err)
}
msg, err :=pubsub.ReceiveMessage()
if err != nil {
    panic(err)
}

fmt.Println(msg.Channel, msg.Payload)

}

在项目"SOCKET"中,有一个订阅者将收听发生的每个发布,并向频道responseclient发布新消息 这是示例代码:

ioApp.on ('connection' , function(socket) {
redisSub.on('new_request', function (channel, message) {
    console.log(channel + ':' + message);

    redisPub.publish("responseclient", JSON.stringify(res));    

}); 

})

如果用户B连接到Socket.IO ,这项工作将顺利进行。但是,如果用户B 处于脱机状态,或者未连接到socket.io,则会等待很长时间,直到我们手动终止或用户B联机为止

我要求的是:

  1. 我们可以在redis pub / sub上创建类似callback的内容吗?如果订户由于离线或其他原因而不接受该消息,则我们关闭连接。这可能吗?
  2. 在Node.Js中,我知道我可以使用超时功能,即关闭订阅或发出任何事件,如果在某个时间,没有收到消息,如何在golang上执行此操作?如果User A处于活动状态或离线状态,我需要通知User B,以便他可以等待另一次创建请求。
  3. 如果什么都没有,你对我的建议是什么?
  4. 我希望我的问题,可以理解,并且可以很好地回答。
    *有些代码可能缺少变量。
    **我正在使用这个库来进行golang redis:go-redis

2 个答案:

答案 0 :(得分:1)

1)Redis中没有回调。

2)在Go中实现超时的常用方法是使用channel并选择 - 其中一个是阻塞的通道,另一个通道在超时时收到消息。可以找到herehere for the docs

的示例

现在对于(3),你有一些方法选择。第一种是使用列表,从一侧推送(发布)和从另一侧推出(订阅)。对于接收器,您可以使用BRPOP BLPOP - 分别从右侧或左侧阻止弹出。您可以将两者结合使用以获得持久消息传递。

现在,PUBSUB的一部分还取决于您要发布的内容。如果您要发布到具有订阅者的频道,当且仅当有用户连接才能接收它(因此该频道只有一个用户),您可以检查来自你的发布命令。它会告诉你它发布了多少客户端。如果频道仅由在线接收者订阅,则返回“1”,如果用户离线则为“0”。

第三个示例是将消息存储在有序集中,时间戳作为分数。这将允许接收器连接并从上次连接时获取消息 - 但这假设某些持久性 - 通常是客户端。您还需要对已排序的集合进行一些清理活动。

在这种情况下需要考虑的其他一些事情是你最终是否使用复制,在这种情况下你必须明确地考虑故障转移 - 尽管在你描述的场景中你真的想要考虑断开连接和重新连接。在my post on reliable PUBSUB有一些具体的例子。

答案 1 :(得分:1)

package main

import (
    "context"
    "fmt"
    "time"

    "github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })

    subscribe := rdb.Subscribe(ctx, "hello")
    subscriptions := subscribe.ChannelWithSubscriptions(ctx, 1)
    go func() {
        var sentCount = 0
        for  {
            rdb.Publish(ctx,"hello",time.Now().UnixNano())
            sentCount++
            if sentCount >300{
                break
            }
        }
    }()
    for  {
        select {
        case sub:=<-subscriptions:
            fmt.Println(sub)
        }
    }



}