天天看點

node mysql retry_nodejs基于async waterfall/retry的出錯重試流程設計

問題來源

最近搞了一個線上服務,涉及到網絡請求、圖檔處理、檔案讀寫等流程,為了解決函數嵌套,我用了async的waterfall方法。結果上線後發現非常不穩定,估計有至少1/4的通路都沒有成功。至此,方才明白穩定可靠服務的重要性。

仔細排查了一下日志,發現有下面幾個問題

- 程式中的error一定要處理

- 每個過程要考慮失敗的情形

第一條程式中的error特别重要,多數情況下是因為忽略了對異常的處理,導緻服務不可用。

第二條是對程式可靠性的保證,一個簡單粗暴的方法是,隻要流程出錯,就重試。

Solution

我們知道,使用waterfall可以保證一序列函數執行的順序,如果函數執行失敗了,會直接中斷處理流程。比較可靠的辦法是,重試流程。

這就用到了async中的retry方法。

var async = require('async');

async.waterfall[

function(callback) {

async.retry({times:5, interval:1000}, function(cb) {

do_task();

var some_err = '';

var some_result = '';

cb(some_err, some_result);

}, function(err, result) {

callback(err, result);

});

},

function(param, callback) {

//類似流程......

},

], function(err, result) {

});

上面的代碼中,最外層的是waterfall,順序執行流程。在每個函數中,可以再加上retry函數,其用法如下:

retry(opts, task, callback)

其中

opts是一個對象,表示重試相關參數,times字段表示重試次數,interval參數表示重試間隔,如果opts隻放一個整數,則表示times,interval預設為0。

task表示要執行的任務,該任務帶有一個回調函數,在執行完成後必須調用,例如上面示例中的cb函數。

callback是retry的回調函數,即retry完成後,對結果進行後續處理。

async中的回調函數參數更像是一種通知機制,就是說在函數執行完成後,傳參到下一流程。例如,在retry過程中的cb,還有waterfall中的callback。

在上面的例子中,callback是外層流程waterfall的回調函數,每個函數執行完成後,通過它将參數傳遞給後續流程。而cb就是retry的回調函數,每次任務執行完成後,由它傳參,并決定是否重試。

這樣,就能實作一個完整的流程控制,并且在每個過程當中,進行出錯重試設計。當然,把retry拿到外層,對waterfall整個進行重試設計,也是可行的。隻是需要處理好業務流程。

nodejs的異步特性在面對複雜業務時,有一些劣勢。盡管有async、Promise等機制可以處理調用嵌套問題。但在業務上,還是需要下一些功夫做好流程設計。