0

I am creating a method that reconnects to RabbitMQ (using amqplib), using recursion and returns a Promise that delivers the connection object. Here is what I have so far:

function connectServiceBus() {
     return new Promise(function (resolve, reject) {
       amqp.connect(process.env.RMQ_CONN + "?heartbeat=60", function(err, conn) {
         if (err) {
           console.error("[AMQP]", err.message);
           //restarts in 1 sec
           return setTimeout(connectServiceBus, 1000);
         }
         conn.on("error", function(err) {
           if (err.message !== "Connection closing") {
             console.error("[AMQP] conn error", err.message);
             reject(Error("[AMQP] conn error"));
           }
         });
         conn.on("close", function() {
           console.error("[AMQP] reconnecting");
           //restarts in 1 sec
           return setTimeout(connectServiceBus, 1000);
         });

         console.log("[AMQP] ServiceBus Connected");
         resolve(conn);
      });
   });
}

I call this method like this:

sbus.connectServiceBus().then( function(conn) {
    console.log("Promise called, connection Object Returned: " + conn);
}).catch (err => {
    console.error("Callback ERROR: " + err);
});

The problem is that if I run this and RabbitMQ is running it works. If RabbitMQ is down, the code reconnects OK but the Promise is never called.

If RabbitMQ is down, if (err) == TRUE and setTimeout(connectServiceBus, 1000) is called. Because of the recursive call, the Promise is never resolved, but not sure how to fix it.

I've tried replacing

return setTimeout(connectServiceBus, 1000);

with

return resolve(connectServiceBus);

but that doesn't work either.

Can anyone explain how I might resolve this, or offer any insight?

Gene Myers
  • 1,230
  • 1
  • 14
  • 31
  • 1
    Good you found a solution, but notice that your `error` and `close` handlers are relatively meaningless as well. When they might run, you already have had fulfilled the promise with `resolve(conn);` and its state cannot change any more. – Bergi Jul 28 '19 at 19:03

1 Answers1

0

I've found a solution that works. I replace

return setTimeout(connectServiceBus, 1000);

with

setTimeout( () => resolve( connectServiceBus() ), 1000 );
return;

EDIT: considering Bergi's comment above, I've updated my code and removed the redundant lines. The return I added simply stopped the code from dropping out of the 'if statement' and executing the final resolve. By adding the 'else', this is no longer needed.

function connectServiceBus() {
     return new Promise(function (resolve, reject) {
       amqp.connect(process.env.RMQ_CONN + "?heartbeat=60", function(err, conn) {
         if (err) {
           console.error("[AMQP]", err.message);
           //restarts in 1 sec
           setTimeout( () => resolve( connectServiceBus() ), 1000 );
         } else {
           console.log("[AMQP] ServiceBus Connected");
           //keep a reference locally so we can close this connection gracefully on err
           amqpConn = conn;
           resolve(amqpConn);
         }
      });
   });
}
Gene Myers
  • 1,230
  • 1
  • 14
  • 31