天天看點

nodejs基于async waterfall/retry的出錯重試流程設計問題來源Solution參考

問題來源

最近搞了一個線上服務,涉及到網絡請求、圖檔處理、檔案讀寫等流程,為了解決函數嵌套,我用了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等機制可以處理調用嵌套問題。但在業務上,還是需要下一些功夫做好流程設計。

參考

https://github.com/caolan/async

文檔

async_demo

Async.retry executes immediately before waiting for interval