6

As it is mentioned in the RabbitMQ docs that tcp connections are expensive to make. So, for that concept of channel was introduced. Now i came across this example. In the main() it creates the connection everytime a message is publised. conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/"). Shouldn't it be declared globally once and there should be failover mechanism in case connection get closed like singleton object. If amqp.Dial is thread-safe, which i suppose it should be

Edited question :

I am handling the connection error in the following manner. In which i listen on a channel and create a new connection on error. But when i kill the existing connection and try to publish message. I get the following error.

error :

2016/03/30 19:20:08 Failed to open a channel: write tcp 172.16.5.48:51085->172.16.0.20:5672: use of closed network connection
exit status 1
7:25 PM

Code :

 func main() {

        Conn, err := amqp.Dial("amqp://guest:guest@172.16.0.20:5672/")
        failOnError(err, "Failed to connect to RabbitMQ")
         context := &appContext{queueName: "QUEUENAME",exchangeName: "ExchangeName",exchangeType: "direct",routingKey: "RoutingKey",conn: Conn}
        c := make(chan *amqp.Error)

        go func() {
            error := <-c
            if(error != nil){                
                Conn, err = amqp.Dial("amqp://guest:guest@172.16.0.20:5672/")            
                failOnError(err, "Failed to connect to RabbitMQ")            
                Conn.NotifyClose(c)                                           
            }            
        }()

        Conn.NotifyClose(c)
        r := web.New()
        // We pass an instance to our context pointer, and our handler.
        r.Get("/", appHandler{context, IndexHandler})
        graceful.ListenAndServe(":8086", r)  

    }
Naresh
  • 5,073
  • 12
  • 67
  • 124
  • As far as I can see the connection is only create one time in the linked samples. You should include the respective code in your question. – Sebastian Mar 23 '16 at 13:17
  • No, but let's say i have a http handler which gets called every time you need to push an object in the queue. So, should we create connection on every request to rabbitmq or use only one connection. – Naresh Mar 23 '16 at 13:19

1 Answers1

11

Of course, you shouldn't create a connection for each request. Make it a global variable or better part of an application context which you initialize once at startup.

You can handle connection errors by registering a channel using Connection.NotifyClose:

func initialize() {
  c := make(chan *amqp.Error)
  go func() {
    err := <-c
    log.Println("reconnect: " + err.Error())
    initialize()
  }()

  conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
  if err != nil {
    panic("cannot connect")
  }
  conn.NotifyClose(c)

  // create topology
}
Sebastian
  • 16,813
  • 4
  • 49
  • 56
  • Could you please elaborate in more detail. I am new to go. So, don't have much idea. I have edited the question. Could you please point out the error where i am wrong. – Naresh Mar 30 '16 at 14:00
  • Are you re-declaring your topology (create channels, etc.) on reconnect? – Sebastian Mar 30 '16 at 14:07
  • No, I am only re-creating the connection. As you can see in the code. I have pasted in my question – Naresh Mar 30 '16 at 14:16
  • You need to re-declare the topology after you have established the connection. You can place this in some function which you can call on startup and after reconnects. – Sebastian Mar 30 '16 at 14:24
  • But i create RabbitMQ channel (not to be confused with go channel) for every request to publish the message. Now how can i re-declare it. Could you please give me the suggestion using code. – Naresh Mar 30 '16 at 15:05
  • I updated my answer. BTW: Your code isn't working for more than one reconnect because nothing is listening on the channel `c` after you have called `Conn.NotifyClose(c)` within the goroutine. – Sebastian Mar 30 '16 at 16:57