Promise中的递归重试

时间:2015-02-11 01:08:21

标签: javascript promise

现在我正在学习如何使用promise编写JavaScript代码。这是我的情况,deliverMessage中的Sender函数尝试与amqp连接。如果成功,则调用publish_发送消息。否则,请在3秒后致电reconnect_重新连接至amqp。代码如下,

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?
};

实际上,无论连接是成功还是失败,都会调用publish_。任何人都可以帮助我如何使用promise实现它吗?

3 个答案:

答案 0 :(得分:2)

我会这样做...

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

答案 1 :(得分:2)

setTimeout不会返回一个承诺,因此无法正常工作。

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

你完成的放置是错误的(实际上你永远不应该使用when.js完成,但这是另一个故事),它总是会像你说的那样被调用。

答案 2 :(得分:1)

Quoting here

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.

我的代码更改如下

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