dongxia1390 2016-09-22 10:32
浏览 55

无法使用msg:=范围msgs阻止Rabbitmq msg(msgs是一个通道)

I copied rabbitmq go example and changed a little to test.

Example URL. It works properly

Code's structure:

 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
 }

But If I put some codes into a function like:

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)
    }
}

The main() could not be blocked to wait msg from server. It will exit right now. Is there any difference between original codes and changed ones ? Thanks a lot !

  • 写回答

1条回答 默认 最新

  • doubeng3216 2016-09-22 13:47
    关注

    This is simple mistake with garbage collection and close defers.

    Assuming your codebase is something similar to this since you ommitted the code from your example.

    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")
    }
    

    Your problem is that you are initialising the connection to Rabbit on the ListenRabbit method and closing it at the same time. So when you range on the channel it is already closed.

    defer conn.Close()

    defer ch.Close()

    These tell go to call the Close methods on the connection and channel once the method ListenRabbit exits. Also by initialising the connection and channel in that method you are leaving all those objects to be garbage collected since no references will be left to them once the moethod finishes.

    You need to initialise all of that in your main so it keeps it open and working or you can return the connection and channel on you method return values but remember to dispose/close them once you are done.

    The code example on the rabbit git repository is the right way to do it but it is just one way of designing the code. You need to understand some of the basic concepts of object oriented programming, coding in go (references, defers, garbage collection etc) and what you looking to do so you can decide what is the best design to use.

    For now just using the example code is good enough.

    评论

报告相同问题?

悬赏问题

  • ¥15 自适应 AR 模型 参数估计Matlab程序
  • ¥100 角动量包络面如何用MATLAB绘制
  • ¥15 merge函数占用内存过大
  • ¥15 Revit2020下载问题
  • ¥15 使用EMD去噪处理RML2016数据集时候的原理
  • ¥15 神经网络预测均方误差很小 但是图像上看着差别太大
  • ¥15 单片机无法进入HAL_TIM_PWM_PulseFinishedCallback回调函数
  • ¥15 Oracle中如何从clob类型截取特定字符串后面的字符
  • ¥15 想通过pywinauto自动电机应用程序按钮,但是找不到应用程序按钮信息
  • ¥15 如何在炒股软件中,爬到我想看的日k线