zoukankan      html  css  js  c++  java
  • nodejs异步请求重试策略总结

    对于node开发同学经常要处理异步请求,然后根据请求的结果或请求成功后的状态码做不同的策略处理,众多策略中最常用的一种就是重试策略。针对重试策略我们往往还需要设定一定的规则,如重试次数、重试时间间隔、总体超时时间、重试判定等。针对以上问题,这里推荐一个工具包:bluebird-retry。
    bluebird-retry基本用法如下:

    var retry = require('bluebird-retry');
    function logFail() {
        console.log(new Date().toISOString());
        throw new Error('bail');
    }
    
    retry(logFail, { max_tries: 4, interval: 500 });
    

    结果如下:

    2014-05-29T23:16:28.941Z
    2014-05-29T23:16:29.445Z
    2014-05-29T23:16:29.946Z
    2014-05-29T23:16:30.447Z
    Error: operation timed out
    

    以上代码逻辑是,如果logFail函数报出异常或出错,则重试四次,每次间隔500毫秒。
    bluebird-retry除了能够捕获异常外,还支持promise形式:

    var Promise = require('bluebird');
    var retry = require('bluebird-retry');
     
    var count = 0;
    function myfunc() {
        console.log('myfunc called ' + (++count) + ' times');
        if (count < 3) {
            return Promise.reject(new Error('fail the first two times'));
        } else {
            return Promise.resolve('succeed the third time');
        }
    }
    
    retry(myfunc)
    .then(function(result) {
        console.log(result);
    });
    

    最终结果:

    myfunc called 1 times
    myfunc called 2 times
    myfunc called 3 times
    succeed the third time
    

    他对promise的支持就为我们的异步请求处理打开了大门,我们可以将bluebirdrequestbluebird-retry三者结合起来,针对异步请求做重试策略:

    var Promise = require('bluebird');
    var request = Promise.promisifyAll(require('request'));
    var retry = require('bluebird-retry');
    var config = require('../config/config');
    var log = require('../log');
    
    module.exports = function(options, method) {
      options.timeout = options.timeout || config.requestTimeout;
    
      var predicate = options.predicate || function(error) {
        log.fatal('GET#' + method +'*retryError#-1#' + options.url + '#error:' + error.stack);
        return error && error.toString() && error.toString().indexOf('ETIMEOUT') > -1;
      };
      delete options.predicate;
    
      return retry(function(){
        log.notice('GET#' + method +'*retry#' + options.url);
        return request.getAsync(options);
      }, {
        max_tries: 3,
        interval: 200,
        backoff: 2,
        predicate: predicate//对错误过滤处理,只有符合条件的错误才会做重试策略,比如超时
      });
    }
    
    

    以上代码就是只针对超时错误做重试处理。
    如果你还有其他场景,比如对返回结果判断status,如果status不为0则重试,那么你只需要在适当时候抛出异常即可。可以参考如下实例:

    function getToken(userId){
        console.log("GET#getToken*start#userId:" + userId);
        log.notice("GET#getToken*start#userId:" + userId);
        return bluebirdRetry(function() {// 获取token,失败则重试三次
            console.log("GET#getToken*retryStart#userId:" + userId);
            log.notice("GET#getToken*retryStart#userId:" + userId);
            return request.getAsync({
               url: config.server.wxToken,
               timeout: config.requestTimeout
            }).then(function(response) {
                var result = JSON.parse(response.body);
                if (!result || result.returnValue !== 0) {// 如果status不为0则重试三次
                    console.log('GET#getToken*retryError#-1#url:' +
                        config.server.wxToken + '#userId:' + user +
                        '#error:' + (result && util.obj2ParamsString(result)));
                    log.fatal('GET#getToken*retryError#-1#url:' +
                        config.server.wxToken + '#userId:' + user +
                        '#error:' + (result && util.obj2ParamsString(result)));
                    throw new Error('getToken Error');
                } else {
                    return result
                }
            });
        }, {
            max_tries: 3,
            interval: 200,
            backoff: 2
        })
        .then(function(result) {
            console.log("GET#getToken*end#userId:" + userId + "#token:" + util.obj2ParamsString(result));
            log.notice("GET#getToken*end#userId:" + userId + "#token:" + util.obj2ParamsString(result));
            return result;
        })
        .catch(function(err) {
            log.fatal("GET#getToken*error#userId:" + userId + "#token:" + config.server.wxToken + '#' + err);
            log.fatal("GET#getToken*error#userId:" + userId + "#token:" + config.server.wxToken + '#' + err);
            return {};
        });
    }
    

    然而有时候并不是所有的情况都想做重试,有些错误情况需要即可失败以便通知开发人员,这时候只要抛出throw new bluebirdRetry.StopError('GetWXImg Error!');即可,示例如下:

    var retry = require('bluebird-retry');
    var i = 0;
    var err;
    var swing = function() {
        i++;
        console.log('strike ' + i);
        if (i == 3) {
            throw new retry.StopError('yer out');
        }
        throw new Error('still up at bat');
    };
     
    retry(swing, {timeout: 10000})
    .caught(function(e) {
        console.log(e.message)
    });
    

    执行结果:

    strike 1
    strike 2
    strike 3
    yer out
    

    关于他的详细文档可以参考:https://www.npmjs.com/package/bluebird-retry
    关于node中错误和异常的处理策略可以参考:http://cnodejs.org/topic/55714dfac4e7fbea6e9a2e5d

  • 相关阅读:
    WCF学习笔记之传输安全
    JavaScript –type
    详解android的号码匹配
    list和用vector区别(Vector相当于是数组,读写快,插入慢)
    拒绝收购邀请,三年专注开发,开源的私有云盘“迷你云”(十人团队在三年时间里靠自筹资金专注开发出来的作品)
    无功不受禄
    如何判断是否安装了VC RUNTIME
    GExpert 1.38 实验版含经典代码格式工具 Berlin 编译版
    初始化IoC容器(Spring源码阅读)
    JavaScript函数绑定
  • 原文地址:https://www.cnblogs.com/dojo-lzz/p/6580753.html
Copyright © 2011-2022 走看看