Reputation: 48366
Now I am learning how to write JavaScript code with promise
. Here is my case, the deliverMessage
function in Sender
try to connect with amqp. If success, then call publish_
to send messages. Otherwise, call reconnect_
to reconnect to amqp
after 3 seconds. The codes are as following,
Sender.prototype.reconnect_ = function( err ) {
console.error('MessageBus disconnected, attempting to reconnect' + err);
this.createFakeChannel_();
return setTimeout( this.deliverMessage.bind(this), 3000);
};
Sender.prototype.deliverMessage = function() {
when(amqp.connect( this.addr_ ))
.with( this )
.then( this.createChannel_ )
.then( this.createExchange_ )
.then( this.handleUnrouteableMessages_ )
.then( this.handleDisconnections_ )
.catch( this.reconnect_ )
.done( this.publish_ ); //? publish_ is invoked in all case?
};
Actually, whether the connection is succeeded or failed, publish_
is called anyway. Could anyone help me how to implement it with promise
?
Upvotes: 1
Views: 1551
Reputation: 48366
Implementing a retry pattern is fairly simple with promises and recursion. The key is ensuring that the promise chain is unbroken. In your example, the call to setTimeout severs the promise chain by initiating a new asynchronous call to deliveryMessage that is outside the promise chain. reconnect also returns the the result of setTimeout immediately.
My codes are changed as following
Sender.prototype.deliverMessage = function ( key, msg ) {
return this
.tryConnect_( this.attempts_, this.retryDelay_ )
.with(this)
.then(function() {
return this.publish_( key, msg );
}).catch( function( e ) {
console.log( e );
});
}
Sender.prototype.retryConnect_ = function( attempts, retryDelay, err ) {
if (attempts === 0) {
console.error('Sender: MessageBus disconnected, attempted to reconnect. Err:' + err);
return when.reject( new Error('Max reconnect attempts exceeded, connection failed'));
}
return when( 'retry' )
.with( this )
.delay( retryDelay )
.then(function() {
return this.tryConnect_( attempts - 1, this.retryDelay_ );
})
}
Sender.prototype.tryConnect_ = function( attempts, retryDelay ) {
return when(amqp.connect( this.addr_ ))
.with( this )
.then( this.createChannel_ )
.then( this.createExchange_ )
.then( this.handleUnrouteableMessages_ )
.then( this.handleDisconnections_ )
.catch( function( e ) {
return this.retryConnect_( attempts, retryDelay, e );
});
};
Upvotes: 1
Reputation: 140210
setTimeout doesn't return a promise so that's not gonna work.
Sender.prototype.reconnect_ = function( err ) {
console.error('MessageBus disconnected, attempting to reconnect' + err);
this.createFakeChannel_();
return when.delay(3000).with(this).then(this.deliverMessage);
};
Sender.prototype.deliverMessage = function () {
when(amqp.connect( this.addr_ ))
.with( this )
.then( this.createChannel_ )
.then( this.createExchange_ )
.then( this.handleUnrouteableMessages_ )
.then( this.handleDisconnections_ )
.then( this.publish_ )
.catch( this.reconnect_ );
};
Your placement of done was wrong (in fact you should never use done with when.js anyway but that's another story), it will always be called as you say.
Upvotes: 2
Reputation: 25034
I would do that like...
Sender.prototype.reconnect_ = function( err, attempt ) {
attempt = attempt || 0;
attempt++;
if(attempt>3){ // change it to whatever value you prefer
throw err;
}
console.error('MessageBus disconnected, attempting to reconnect' + err);
this.createFakeChannel_();
return setTimeout( this.deliverMessage.bind(this, attempt ), 3000);
};
Sender.prototype.deliverMessage = function(attempt) {
when(amqp.connect( this.addr_ ))
.with( this )
.then( this.createChannel_ )
.then( this.createExchange_ )
.then( this.handleUnrouteableMessages_ )
.then( this.handleDisconnections_ )
.then( this.publish_, function(err){
this.reconnect_(err, attempt);
});
};
Upvotes: 2