【问题标题】:Recursive retry in PromisePromise 中的递归重试
【发布时间】:2015-02-12 20:03:30
【问题描述】:

现在我正在学习如何使用 promise 编写 JavaScript 代码。这是我的情况,Sender 中的deliverMessage 函数尝试与 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 实现它?

【问题讨论】:

  • 你试过.then( this.handleDisconnections_ ).then(this.publish_, this.reconnect_)吗?
  • @mido22 - 但可能需要一些不会让这个循环永远持续每 3 秒重试一次的东西。也许在放弃之前重试的最大次数。
  • @jfriend00 我现在的答案怎么样,我已经添加了一个参数来处理尝试次数...
  • catch“成功”处理了 Promise(除非它自己抛出),这意味着链式 then(包括 done)将对 @ 的已实现/已解决结果进行操作987654334@。如果您希望承诺“保持”在拒绝状态,一种简单的方法是在 reconnect_ 中重新抛出错误。

标签: javascript promise


【解决方案1】:

我会这样做......

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

    你的 done 位置是错误的(事实上你永远不应该在 when.js 中使用 done,但那是另一回事),它总是会按照你说的那样被调用。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2021-04-29
        • 2019-01-25
        • 2019-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-24
        • 2015-11-14
        • 2021-02-03
        相关资源
        最近更新 更多