對於node開發同窗常常要處理異步請求,而後根據請求的結果或請求成功後的狀態碼作不一樣的策略處理,衆多策略中最經常使用的一種就是重試策略。針對重試策略咱們每每還須要設定必定的規則,如重試次數、重試時間間隔、整體超時時間、重試斷定等。針對以上問題,這裏推薦一個工具包:bluebird-retry。
bluebird-retry基本用法以下:node
var retry = require('bluebird-retry'); function logFail() { console.log(new Date().toISOString()); throw new Error('bail'); } retry(logFail, { max_tries: 4, interval: 500 });
結果以下:npm
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形式: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的支持就爲咱們的異步請求處理打開了大門,咱們能夠將bluebird
,request
,bluebird-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!');
便可,示例以下:ui
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) });
執行結果:url
strike 1 strike 2 strike 3 yer out
關於他的詳細文檔能夠參考:https://www.npmjs.com/package/bluebird-retry
關於node中錯誤和異常的處理策略能夠參考:http://cnodejs.org/topic/55714dfac4e7fbea6e9a2e5dcode