如何让 Go 应用程序等待 Redis 列表中的数据可用?

How to make a Go app wait for data to become available in a Redis list?

我有一个使用 Radix Redis client for Go 的 Go 应用程序。它的工作是 运行 作为后台进程并等待 Redis 列表将项目添加到其中进行处理。

背景(随意跳过):我有一个 Node.js 网络应用程序需要从外部 API 请求数据已知至少需要整整一秒或更长时间才能做出响应。数据不是立即需要的,所以我让 Node 应用程序将一个项目添加到 Redis 列表,然后继续处理重要的事情。同时,我有一个 Go 应用程序,它应该在幕后 运行 并在每次发现项目已添加到列表时做一些工作。

现在它只是一个连接到 Redis 的 main 函数,并使用 Redis BRPOP 命令检查列表中是否包含项目(因为我希望 Redis 在等待时阻塞求职)。 运行 该程序导致建立连接,然后...

我需要 Go 应用程序只是坐在那里等待新项目,我真的不想求助于轮询,特别是因为 BRPOP 和 BLPUSH 命令是专门制作的,所以应用程序不需要轮询。

我目前的解决方案是只创建一个无限循环,运行BRPOP 命令永远一遍又一遍。这感觉是错误的做法。

这是到目前为止的整个程序(我是 Go 的新手,但不是编程的新手,所以不要笑得太厉害):

package main

import (
  "fmt"
  "github.com/fzzy/radix/redis"
)

func main() {
  client, err := redis.Dial("tcp", "localhost:6379")

  if err != nil {
    fmt.Println("An error message just for debug purposes")
  } else {
    // Here I check to make sure the server is responding
    ping := client.Cmd("PING")
    fmt.Println(ping) // Just to be sure I'm doing things right

    for {
      fmt.Println("Looking for a new Q item...")
      workItem, err := client.Cmd("BRPOP", "q:test").Str()

      if err != nil {
        fmt.Println("No error, " + workItem)
      }
    }
  }
}

那么让 Go 应用程序等待 Redis 列表中的数据可用的正确方法是什么?

更新: 根据一些评论,我将进一步解释我的期望和正在发生的事情。

我对阻塞 Redis 命令的理解是,它只会暂停调用它的程序,直到它需要 return。所以在我的例子中,当 运行 程序在队列中没有项目时,程序打印:

Looking for a new Q item...
No error, 

它无限地打印上面的内容,这是有道理的,因为我有一个永无止境的 for 循环 但是 因为我正在使用阻塞命令,我希望它的行为更像一推。我希望循环只是暂停并等到队列中有一个项目,然后再继续下一次迭代。我担心它即使没有队列项也会继续循环,最终进程将开始不必要地消耗资源并减慢 Redis,因为 BRPOP 命令不断涌现(尽管它是一个阻塞命令)。

所以我想现在新的问题是 - 在等待 Redis 列表(或我的临时队列)中的新项目时,是否有更好的方法来保持 Go 程序 运行ning? - 运行以当前形式使用此程序会消耗比应有的更多资源 and/or 会降低 Redis 性能吗?

已解决

感谢@JimB 关于 "error you're ignoring..." 的问题,我再次查看了代码以确保我没有遗漏一些明显的东西。我是:原来在我的循环中我已经切换了错误和成功处理代码。所以每次出错时,我都会向控制台打印一条成功消息,这样我就可以看到程序内部发生了什么。切换代码并正确处理错误后,我发现我在调用 BRPOP 时参数太少了。我修复了代码,现在循环将一直挂在那里,直到列表中有要处理的内容。

更正以下行:

// We now import "log" now as well
// Inside the for loop...
if err != nil {
  log.Fatal(err) // This alerted me to the wrong # of arguments issue
} else {
  fmt.Println("No error to be had " + workItem) // Will not print until there is an item in the list
}

我想我一直都做对了。但是,如果有任何关于性能或更好的方法的评论或建议,我仍然会听到并很乐意听到它们。

@JimB 实至名归。我切换了错误和成功处理程序。我给 BRPOP 命令的参数太少了。循环中的这段代码修复了它:

// We now import "log" now as well
// Inside the for loop...
if err != nil {
  log.Fatal(err) // This alerted me to the wrong # of arguments issue
} else {
  fmt.Println("No error to be had " + workItem) // Will not print until there is an item in the list
}

谢谢大家