如何阻止正在侦听RethinkDB更改源的goroutine?

时间:2016-07-04 01:12:50

标签: go rethinkdb goroutine

我试图找出如何使用golang的RethinkDB更改源。 我的具体问题是如何阻止听取改变的goroutine 数据库。例如,请参阅下面的函数getData()。我从一个处理程序运行它 通过调用go getData(c)来发挥作用。每当数据库更新时,记录就是 传递给通道c,然后传递给处理函数并发送到客户端 使用SSE技术。我的问题是:当客户端断开连接时,我知道如何停止和退出 处理函数;但是运行getData()函数的goroutine仍在运行。什么可以 我要关闭它吗?基于stackoverflow的其他答案,我能想到的一个解决方案是 发送信号以关闭另一个通道上的goroutine并使用select语句来处理此问题 信号。例如,我可以替换

    for cur.Next(&rec) {
        c <- rec
    }

在下面的函数定义中:

    for cur.Next(&rec) {
        select {
         case <- closesignal:
            return
         default:
            c <- rec
        }
    }

其中,closesignal是作为getData()的第三个参数给出的另一个通道 当客户端断开连接时,处理程序在此通道上发送消息。

这种方法的问题是:如果特定rethinkdb查询的结果怎么办? 从不更新。在这种情况下,将不会输入for cur.Next(&rec)循环,并且不会使用closesignal。 这个goroutine会继续运行吗?如果是这样,我该如何阻止这个goroutine?

getData()功能

func getData(session *r.Session, c chan interface{}) {
    var rec interface{}

    changesOpts := r.ChangesOpts{
        IncludeInitial: true,
    }

    cur, err := r.DB(DBNAME).Table("test").Changes(changesOpts).Run(session)
    if err != nil {
        log.Println(err)
        return
    }
    defer cur.Close()

    defer func() {
        fmt.Println("exiting getData goroutine()...")
    }()


    for cur.Next(&rec) {
        c <- rec
    }

}

3 个答案:

答案 0 :(得分:1)

您可以通过关闭光标来停止正在侦听更改源的goroutine。例如,此代码将在关闭之前收听更改请求10秒:

go func() {
    time.Sleep(10 * time.Second)
    cur.Close()
}()

for cur.Next(&rec) {
    c <- rec
}

// Loop exits as the cursor has been closed

答案 1 :(得分:0)

您应通过context停止更改供稿。您可以将上下文传递给RunOpts。这将立即关闭您的更改供稿。

答案 2 :(得分:0)

我认为处理这种情况的最好方法是使用contexts和goroutine来关闭光标。 这里有一些good documentation from the go blog关于上下文的信息。

这是带有上下文的实现示例:

func AreThereChanges(ctx context.Context) error {
    cursor, err := r.Table("something").
        Changes().
        Run(db.Session)

    if err != nil {
      //manage error
    }

    go func(ctx context.Context) {
        <-ctx.Done()
        cursor.Close()
    }(ctx)

    var changeFeed map[string]interface{}
    for cursor.Next(&changeFeed) {
        if changeFeed["old_val"] != nil {
          //do something
        }

        if changeFeed["new_val"] != nil {
          //do something
        }
    }