我复制了rabbitmq go示例并改变了一点进行测试。
Example URL。它运作正常
代码的结构:
func main() {
//dial rabbit server
//declare channel/exange/queue
msgs, err := ch.Consume() //typeof(msgs)=<-chan Delivery
forever := make(chan bool)
go func() {
for d := range msgs {
log.Printf("Received a message: %s", d.Body)
}
}()
log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
<-forever
}
但是,如果我将一些代码放入如下函数中:
func ListenRabbit() (<-chan Delivery, error) {
//dial rabbit server
//declare channel/exange/queue
msgs, err := ch.Consume() //typeof(msgs)=<-chan Delivery
return msgs, err
}
func main(){
msgs, _ := ListenRabbit()
for d := range msgs {
log.Printf("Received a message: %s", d.Body)
}
}
无法阻止main()从服务器等待msg。它现在会退出。原始代码和更改代码之间有什么区别吗? 非常感谢!
答案 0 :(得分:0)
这是垃圾收集和密切推迟的简单错误。
假设您的代码库与此类似,因为您省略了示例中的代码。
package main
import (
"log"
"github.com/streadway/amqp"
)
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
func ListenRabbit() (<-chan amqp.Delivery, error) {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()
ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close()
q, err := ch.QueueDeclare(
"hello", // name
false, // durable
false, // delete when usused
false, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue")
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
true, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
failOnError(err, "Failed to register a consumer")
return msgs, err
}
func main() {
msgs, _ := ListenRabbit()
for d := range msgs {
log.Printf("Received a message: %s", d.Body)
}
log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
}
您的问题是您正在使用ListenRabbit方法初始化与Rabbit的连接并同时关闭它。因此,当您在频道上调整范围时,它已经关闭。
defer conn.Close()
defer ch.Close()
一旦方法connection
退出,这些告诉将调用channel
和ListenRabbit
上的关闭方法。此外,通过初始化该方法中的连接和通道,您将使所有这些对象都被垃圾收集,因为一旦moethod完成,就不会有任何引用。
你需要在你的主要内容中初始化所有内容,以便它保持打开和工作状态,或者你可以返回连接和通道上的方法返回值,但记得在完成后处理/关闭它们。
rabbit git repository上的代码示例是正确的方法,但它只是设计代码的一种方式。您需要了解面向对象编程的一些基本概念,go中的编码(引用,延迟,垃圾收集等)以及您要做的事情,以便您可以决定使用哪种最佳设计。
现在只需使用示例代码即可。