關于node-redis中quit()的優(yōu)雅退出遇到forEach的問題

在redis的node客戶端中官方文檔上描述客戶端斷開與redis的連接的方式有兩種:

  • client.end()所謂的‘二話不說直接暴力斷開’;官方文檔上是這樣描述end()方法的:

Forcibly close the connection to the Redis server. Note that this does not wait until all replies have been parsed. If you want to exit cleanly, call client.quit() as mentioned above.
You should set flush to true, if you are not absolutely sure you do not care about any other commands. If you set flush to false all still running commands will silently fail.

大體上的意思就是說end()方法不會等到所有的答復都被解析之后才斷開和redis的連接,他會立刻斷開與數(shù)據(jù)庫的連接竣稽,若是你想要優(yōu)雅的退出你應該選擇quit()敞掘。

  • quit()方法在官方文檔上是這樣描述的:

This sends the quit command to the redis server and ends cleanly right after all running commands were properly handled. If this is called while reconnecting (and therefore no connection to the redis server exists) it is going to end the connection right away instead of resulting in further reconnections! All offline commands are going to be flushed with an error in that case.

主旨是說調用quit命令將所有運行的命令正確處理后,將quit命令發(fā)送到redis服務器,并將其完全正確地結束辛臊。就是所謂的優(yōu)雅退出
如果在重新連接時調用(即redis服務器的連接不存在)疹味,則它將立即結束連接仅叫,而不會導致進一步的重新連接,在這種情況下糙捺,所有脫機命令將被刷新诫咱,并出現(xiàn)錯誤。

因為有所謂的優(yōu)雅退出才會有如下的方式寫法:

var redis = require("redis");
var client = redis.createClient({detect_buffers: true});
 
client.set("foo_rand000000000000", "OK");
 
// This will return a JavaScript String 
client.get("foo_rand000000000000", function (err, reply) {
    console.log(reply.toString()); // Will print `OK` 
});
 
// This will return a Buffer since original key is specified as a Buffer 
client.get(new Buffer("foo_rand000000000000"), function (err, reply) {
    console.log(reply.toString()); // Will print `<Buffer 4f 4b>` 
});
client.quit();

這段代碼中的client.set()和client.get()無疑都是異步的代碼洪灯,若是此處用的是client.end()替換掉client.quit()無疑會在命令未能正確處理之前就會于數(shù)據(jù)庫斷開從而出現(xiàn)錯誤坎缭,而quit()就會處理完所有命令回復之后才安全的斷開與數(shù)據(jù)庫的連接。

Redis中的quit()和end()就相應類比為在node-mysql中的兩種與數(shù)據(jù)庫斷開的方式end()和destroy()方法签钩。

接下來就是我在寫代碼的時候自以為quit優(yōu)雅退出遇到的問題掏呼,原始代碼如下:

/**
 * 往某一個有序集合里面增加一個成員,如果這個成員存在則將其分數(shù)加1铅檩,如果不存在則直接加入一個成員憎夷;
 * 判斷members是否已經在sortedSet中存在了
 * 由于有序集合中不像簡單集合中有SISMEMBER直接判斷是否存在的命令
 * 這里我使用 ’zscore key memberName‘ 的方式如果返回為null則表明他不存在
 * @param {String} 鍵的keyName
 * @param {Array}  
 * @param {Function}
 */

redisDB.addToSortedSet = (keyName, args, callback) => {
        let client = redisDB.connect();
        args.forEach((element, index) => {
            let params = [];
            params.push(keyName, element);
            client.zscore(params, (err, results) => {
                if (err) {
                    logger.writeDebug(err);
                    callback(err);
                } else {
                    if (results) { //成員已經存在
                        let params = [];
                        params.push(keyName, 1, element);
                        client.zincrby(params, (err, res) => {
                            if (err) {
                                logger.writeDebug(err);
                                callback(err);
                            } else {
                                callback(null, res);
                            }
                        })

                    } else { //成員不存在直接插入,初始分數(shù)為0
                        let params = [];
                        params.push(keyName, 0, element);
                        client.zadd(params, (err, res) => {
                            if (err) {
                                logger.writeDebug(err);
                                callback(err);
                            } else {
                                callback(null, res);
                            }
                        })

                    }
                }
            })
        });
     client.quit();
    }

這段代碼主要的結構就是我在建立了node與Redis的連接之后跟了一個對數(shù)組的forEach循環(huán),然后再循環(huán)體中有嵌套兩層的異步回調函數(shù)昧旨;(Tips:在寫這段的時候我是需要去判斷數(shù)組內的元素在redis的有序集合中是不是已經存在拾给,由于有序集合不像是Set結構那樣有一條命令去直接判斷元素是否是Set的成員(sismember命令)祥得,所以我用了zscore key memberName 如果成員存在則會返回這個成員對應的score,如果這個成員不存在則就會返回null蒋得,以此判斷是否存在)

這段代碼在我測試調用插入兩條數(shù)據(jù)的時候報出了這樣的錯誤:

{ AbortError: 
Stream connection ended and command aborted.
It might have been processed.
  code: 'NR_CLOSED',
  command: 'ZINCRBY',}

說我的連接斷了级及,執(zhí)行到ZINCRBY的時候命令中斷了........

原來“優(yōu)雅退出”也并不是完全讓人省心......(我好想抖段子。额衙。饮焦。)

我仔細看了一下報錯,我插入了兩條數(shù)據(jù)庫里都存在數(shù)據(jù)窍侧,應該到最后走的都是最里層ZINCRBY的那個異步分支县踢,而報錯的就是forEach中兩條數(shù)數(shù)據(jù)都是執(zhí)行到ZINCRBY報出得Stream connection ended and command aborted.

當時我的腦子里過的第一個單純的想法是forEach會不會是個異步的,因為它長得像疏之,而quit()優(yōu)雅退出的是redis自己的命令回調殿雪,并不會管別的異步回調,然而forEach雖然傳了一個函數(shù)但是它本身并不是異步的,測試代碼如下:

let args=[2,3,4];
args.forEach( (element, index)=> {
    console.log(element);
});
console.log(1);

打印結果:

2
3
4
1

并不是想象中的異步的锋爪;必然還是要試一下forEach中只有一層異步的情況的丙曙,試完問題就必然都對上號了

redisDB.addToSortedSet = (keyName, args, callback) => {
        let client = redisDB.connect();
        args.forEach((element, index) => {
            let params = [];
            params.push(keyName, element);
            client.zscore(params, (err, results) => {
                if (err) {
                    logger.writeDebug(err);
                    callback(err);
                } else {
                    console.log(results);
                }
            })
        });
       client.quit();
    }

這一次執(zhí)行之后沒毛病,傳進去有兩個元素的args其骄,因為存在所以就很優(yōu)雅的返回了兩個成員的分數(shù)亏镰,看來優(yōu)雅的照顧也是有限的,我只負責你一層所有的命令全部給你結果拯爽,再嵌套一層就不會管你了:)

遂...

代碼改為如下

redisDB.addToSortedSet = (keyName, args, callback) => {
        let client = redisDB.connect();
        args.forEach((element, index) => {
            let params = [];
            params.push(keyName, element);
            client.zscore(params, (err, results) => {
                if (err) {
                    logger.writeDebug(err);
                    callback(err);
                } else {
                    if (results) { //成員已經存在
                        let params = [];
                        params.push(keyName, 1, element);
                        client.zincrby(params, (err, res) => {

                            client.quit();

                            if (err) {
                                logger.writeDebug(err);
                                callback(err);
                            } else {
                                callback(null, res);
                            }
                        })

                    } else { //成員不存在直接插入,初始分數(shù)為0
                        let params = [];
                        params.push(keyName, 0, element);
                        client.zadd(params, (err, res) => {

                            client.quit();

                            if (err) {
                                logger.writeDebug(err);
                                callback(err);
                            } else {
                                callback(null, res);
                            }
                        })

                    }
                }
            })
        });
    }

這下沒毛病了.......在最里層異步函數(shù)的回調里再調用client.quit()索抓,就能保證請求都被處理完了之后再“優(yōu)雅斷開”
(最后很想說,第一次在博客網站上輸出毯炮,可能還是跟以前在wiki上記的片面的不太一樣逼肯,以后也會養(yǎng)成經常寫博客記錄的習慣,因為水平有限表達上可能也有待提高桃煎,更希望能夠得到大家的批評指正篮幢,大家一起在學習路上共同進步!)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末为迈,一起剝皮案震驚了整個濱河市三椿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌葫辐,老刑警劉巖搜锰,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異耿战,居然都是意外死亡蛋叼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門剂陡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸦列,“玉大人租冠,你說我怎么就攤上這事鹏倘∈磬停” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵纤泵,是天一觀的道長骆姐。 經常有香客問我,道長捏题,這世上最難降的妖魔是什么玻褪? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮公荧,結果婚禮上带射,老公的妹妹穿的比我還像新娘。我一直安慰自己循狰,他們只是感情好窟社,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绪钥,像睡著了一般灿里。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上程腹,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天匣吊,我揣著相機與錄音,去河邊找鬼寸潦。 笑死色鸳,一個胖子當著我的面吹牛,可吹牛的內容都是我干的见转。 我是一名探鬼主播命雀,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼池户!你這毒婦竟也來了咏雌?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤校焦,失蹤者是張志新(化名)和其女友劉穎赊抖,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寨典,經...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡氛雪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了耸成。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片报亩。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡浴鸿,死狀恐怖,靈堂內的尸體忽然破棺而出弦追,到底是詐尸還是另有隱情岳链,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布劲件,位于F島的核電站掸哑,受9級特大地震影響,放射性物質發(fā)生泄漏零远。R本人自食惡果不足惜苗分,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望牵辣。 院中可真熱鬧摔癣,春花似錦、人聲如沸纬向。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽罢猪。三九已至近她,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間膳帕,已是汗流浹背粘捎。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留危彩,地道東北人攒磨。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子熙含,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內容

  • 安全性 設置客戶端連接后進行任何其他指令前需要使用的密碼。 警告:因為redis 速度相當快拼坎,所以在一臺比較好的服...
    OzanShareing閱讀 1,668評論 1 7
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)完疫,斷路器泰鸡,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • 1.1 資料 ,最好的入門小冊子壳鹤,可以先于一切文檔之前看盛龄,免費。 作者Antirez的博客,Antirez維護的R...
    JefferyLcm閱讀 17,032評論 1 51
  • linux 啟動 redis:cd /usr/local/redis-3.2.0src/redis-server ...
    晏子小七閱讀 9,817評論 0 11
  • 想要一個人很奇怪嗎余舶?畢業(yè)一年后啊鸭,工作不上不下,生活沒著沒落匿值。小城市里赠制,女人好像除了結婚別無選擇。每當別人問起千扔,你今...
    故鄉(xiāng)的云啊閱讀 133評論 0 0