2015-02-11 34 views
1

現在我正在學習如何使用promise編寫JavaScript代碼。這裏是我的情況,Sender中的deliverMessage函數嘗試與amqp連接。如果成功,則撥打publish_發送消息。否則,請在3秒鐘後致電reconnect_重新連接至amqp。該代碼如下,Promise中的遞歸重試

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來實現它嗎?

+0

你嘗試過'''。然後(this.handleDisconnections_)。然後(this.publish_,this.reconnect_) '''? – mido 2015-02-11 01:16:19

+0

@ mido22 - 但可能需要一些東西,不會讓這個循環永遠每隔3秒重試一次。在放棄之前可能是最大數量的重試。 – jfriend00 2015-02-11 01:23:07

+0

@ jfriend00現在我的答案,我已經添加了一個參數來照顧的嘗試次數... – mido 2015-02-11 01:31:29

回答

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); 
     }); 
}; 
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做反正但這是另一回事),它會像你說的總是被調用。

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