Mongoose: ์ฝœ๋ฐฑ์ด ์ค‘์ง€๋จ

์— ๋งŒ๋“  2016๋…„ 09์›” 13์ผ  ยท  53์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: Automattic/mongoose

๋ช‡ ๋…„ ๋™์•ˆ mongoose ์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ ์ตœ๊ทผ์—๋Š” ์—ฐ๊ฒฐ์ด ์‚ฌ๋ผ์ง€๋Š” ๊ฒƒ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋งŽ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ ์„ค์ •

// Connecting to MongoDB 3.2.1
var connString = "mongodb://xxxxx:xxxxx<strong i="8">@xxxxx</strong>:xxxx,xxxx:xxxx/xxx?ssl=true";
var connOptions = {
  "mongos": { "ssl": true, "sslValidate": false }
};
mongoose.connect(connString, connOptions, function(err, db) {
  if(err) { console.log("Error connecting to db: "+err); }
});

๋ฌธ์ œ

๋ชฝ๊ตฌ์Šค๋Š” ๋‹ค์‹œ ์ „ํ™”๋ฅผ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ๋ฉ”๋ชจ๋ฆฌ/cpu๊ฐ€ ๋‚ด ์„œ๋ฒ„ ๋ฐ db์—์„œ ์ •์ƒ์ด๋ฉฐ ๋‹ค๋ฅธ ์„œ๋ฒ„์—์„œ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋ฉด ํ•ญ์ƒ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

db.Something.count({}, callback);

๋ฒ„์ „

mongoose 4.4.11 , mongoose.connection.readyState === UNAUTHORIZED ์ฝœ๋ฐฑ์ด ์ค‘์ง€๋  ๋•Œ.

๊ทธ๋ž˜์„œ mongoose 4.6.0 ์—…๊ทธ๋ ˆ์ด๋“œ ํ–ˆ์ง€๋งŒ 4์‹œ๊ฐ„ ์ด๋‚ด์— ์ฝœ๋ฐฑ์ด ๋‹ค์‹œ ์ค‘์ง€๋˜์—ˆ์œผ๋ฉฐ ์ด์ œ mongoose.connection.readyState === CONNECTED ์ž…๋‹ˆ๋‹ค.

๋ชจ๋“  ์•„์ด๋””์–ด

์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

๋” ๋งŽ์€ ๋””๋ฒ„๊น… ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ๋ ค์ฃผ์„ธ์š”.

underlying library issue

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๋ถˆํ–‰ํžˆ๋„ mongodb ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ๋ฆด๋ฆฌ์Šค๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋‹ค์‹œ ๋ฐ€์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฃ„์†กํ•˜๊ณ  ๊ธฐ๋‹ค๋ ค์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค :+1: ๐ŸŒด

๋ชจ๋“  53 ๋Œ“๊ธ€

๋…๋ฆฝ ์‹คํ–‰ํ˜•, ๋ณต์ œ๋ณธ ์„ธํŠธ ๋˜๋Š” ๋ถ„ํ• ๋œ ํด๋Ÿฌ์Šคํ„ฐ์— ์—ฐ๊ฒฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ๋˜ํ•œ SSL์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด๊ฒƒ์€ ์ง€๋‚œ ๋ฉฐ์น  ๋™์•ˆ ๋‚˜์—๊ฒŒ ํฐ ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค. ์‹คํ–‰ ์ค‘์ธ ๋ชจ๋“  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋” ๋Š๋ฆฌ๊ณ  ๋” ๋Š๋ฆฐ ์ด๋ฒคํŠธ ๋ฃจํ”„๋กœ ๋๋‚˜๊ณ  ์ „์ฒด ์‹œ์Šคํ…œ์—์„œ ์ง€์—ฐ ์‹œ๊ฐ„์ด ์ฆ๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋…ธ๋“œ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋ฉด ๋งค๋ฒˆ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์œผ๋ฉฐ ๋ช‡ ๋ถ„ ๋˜๋Š” ๋ช‡ ์‹œ๊ฐ„ ๋™์•ˆ ์ž‘๋™ํ•œ ํ›„์— ๋‹ค์‹œ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

mongoose 4.5.10์œผ๋กœ ๋˜๋Œ๋ฆฌ๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • ๋ณต์ œ๋ณธ ์„ธํŠธ์— ์—ฐ๊ฒฐ
  • SSL ์‚ฌ์šฉ

์—ฌ๊ธฐ 4.6.0๊ณผ ์œ ์‚ฌํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณต์ œ ์„ธํŠธ์— ์—ฐ๊ฒฐํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ SSL์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ํ™•์‹คํ•ฉ๋‹ˆ๋‹ค.

FWIW, 4.6.0์€ ์ง€์†์ ์œผ๋กœ ์—ฐ๊ฒฐ์„ ๋Š์—ˆ์Šต๋‹ˆ๋‹ค. 4.5.10์ด ์ข‹์Šต๋‹ˆ๋‹ค.

@djanowski ์—ฐ๊ฒฐ ์ฝ”๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€, ๊ฐ€์ง€๊ณ  ์žˆ๋Š” mongodb์˜ ๋ฒ„์ „๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@ vkarpov15 ์ €๋Š” MongoDB 3.2.6์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ ์˜ต์…˜:

auth: {
  authMechanism: 'SCRAM-SHA-1',
},
mongos: {
  ssl: true,
  sslValidate: true,
  sslCA: [cert],
},

๋‹จ์ผ ๋ชฝ๊ณ  ๋˜๋Š” ๋‹ค์ค‘ ๋ชฝ๊ณ ?

์—ฌ๋Ÿฌ ๋ชฝ๊ณ . Compose Mongo ๋ฐฐํฌ ์‚ฌ์šฉ.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋Š” ๋‹ค๋ฅธ ์ž‘์—…์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ด๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์„ ์ฐจ๋‹จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค...

์ฝ”๋“œ๋ฅผ ๋ณด์ง€ ์•Š๊ณ ๋Š” ์‹ค์ œ ๊ฐ€์„ค์„ ์„ธ์šฐ๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. mongoose.connect ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒฝ์šฐ ์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‹œ์ž‘ํ•  ๋•Œ mongoose.connection.readyState ๊ฐ’์„ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ชจ๋“  mongoose ์ž‘์—…์— ๋Œ€ํ•ด ์ฝ˜์†”์— ๋””๋ฒ„๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ์ธ์‡„ํ•˜๋Š” mongoose ๋””๋ฒ„๊ทธ ๋ชจ๋“œ mongoose.set('debug', true) ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ฉ”์‹œ์ง€๊ฐ€ ์ธ์‡„ ์ค‘์ธ์ง€ ์—ฌ๋ถ€๋Š” ๋””๋ฒ„๊ทธ์— ํ™•์‹คํžˆ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@vkarpov15 ์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. https://gist.github.com/sommestad/c0c6a7fa4feaadf84ecbb59cc3432c90
๊ฐœ์ธ ๋ชจ๋“ˆ์˜ ์ผ๋ถ€์ด๋ฏ€๋กœ Gist.

_(์—ฐ๊ฒฐ ๋ž˜ํ•‘ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ์—ญ์‚ฌ์ ์œผ๋กœ mongoose์—์„œ ์ž˜ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜๋˜ ๋‹ค๋ฅธ private NPM ๋ชจ๋“ˆ์—์„œ ์—ฐ๊ฒฐ์ด ๊ฐ€๋” ์žฌ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.)_

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์—ฐ๊ฒฐ ์ƒํƒœ ๋กœ๊น…์„ ํ™œ์„ฑํ™”ํ–ˆ์ง€๋งŒ ์—ฐ๊ฒฐ ์ž์ฒด๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค(์ตœ์†Œํ•œ ์ด๋ฒคํŠธ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ). ๊ทธ๋ž˜์„œ ํด๋ผ์ด์–ธํŠธ์˜ ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง„ ๊ฒƒ ๊ฐ™์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

URI์—์„œ replicaSet ๋กœ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋Œ€์ƒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” Compose Deployment ). ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด SSL์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํŠธ๋ž˜ํ”ฝ์€ AWS NAT ๊ฒŒ์ดํŠธ์›จ์ด๋ฅผ ํ†ตํ•ด ๋ผ์šฐํŒ…๋ฉ๋‹ˆ๋‹ค. AWS NAT๋Š” ์œ ํœด ์‹œ๊ฐ„ ์ œํ•œ์ด 5๋ถ„์ด์ง€๋งŒ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋Š” ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์€ ๊ฒฝ์šฐ์—๋„ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜์—๊ฒŒ ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ, ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์„ ํ•ด๊ฒฐ ํ–ˆ์Šต๋‹ˆ๊นŒ?

@youth7 ์•„๋‹ˆ ์•„์ด๋””์–ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ž‘์„ฑ ๋ฐฐํฌ์—๋„ ์—ฐ๊ฒฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์‹ญ์‹œ์˜ค

์ด ๋ฌธ์ œ์˜ ์›์ธ์„ ์ฐพ๊ธฐ ์œ„ํ•ด ๋” ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์กฐ์‚ฌํ•  ์ˆ˜ ์žˆ๋Š” ์ด๋ก ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@sommestad๋Š” ๊ตฌ์ฒด์ 

mongoose 4.7.2 ์‹œ๋„ํ–ˆ์ง€๋งŒ 48์‹œ๊ฐ„ ํ›„์—๋„ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์‹œ์ ์—์„œ ์ €๋Š” 4.4.11 ์ž์ฒด์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋กœ๊ทธ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ๋ชจ ์„œ๋ฒ„์— 4.7.2 ๋ฅผ ์„ค์น˜ํ–ˆ์ง€๋งŒ ๋ฌธ์ œ ์—†์ด 2์ฃผ ๋™์•ˆ ์‹คํ–‰๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ/์—ฐ๊ฒฐ/๊ธฐํƒ€์˜ ๋ณผ๋ฅจ์ด ๋ฌธ์ œ๋ฅผ ์œ ๋ฐœํ•ฉ๋‹ˆ๊นŒ?

์ผ๋‹จ ๋ฐœ์ƒํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด ์ด๋ฅผ ์žฌํ˜„ํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ์ฟผ๋ฆฌ์˜ ์ฝœ๋ฐฑ์ด ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

db.Something.find({}, callback); //this callback is never fired

๋‚ด๊ฐ€ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด ์ผ์ด ๋ฐœ์ƒํ•˜๋ฉด mongoose.connection.readyState === CONNECTED

๊ธฐ์ด ํ•œ. mongodb ๋กœ๊ทธ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ์‹œ์ ์˜ mongodb ์„œ๋ฒ„ ๋กœ๊ทธ๋ฅผ ๋คํ”„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ DB ๋กœ๊ทธ๋ฅผ ์Šค์บ”ํ–ˆ๋Š”๋ฐ ๋น„์ •์ƒ์ ์ธ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ ์ˆ˜, ์—ฐ๊ฒฐ ๋Š๊น€, ์—ฐ๊ฒฐ ๋ฌธ์ œ ๋“ฑ์˜ ๋ฌธ์ œ๋Š” ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋˜ํ•œ ์ˆœ์„œ๊ฐ€ ์ž˜๋ชป๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์—†์—ˆ๋˜ Compose์— ์—ฐ๋ฝํ–ˆ์Šต๋‹ˆ๋‹ค.

@bendytree HTTP ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ๋ฐ๋ชจ ์„œ๋ฒ„์— ์•ฝ๊ฐ„์˜ ๋ณผ๋ฅจ์„ ๋˜์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@bendytree ๋˜ํ•œ Node์˜ ๋ชจ๋“  ๋ฆด๋ฆฌ์Šค ๋ผ์ธ(4.x, 6.x ๋ฐ 7.x)์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๊นŒ?

@vkarpov15 ์ตœ์‹  MongoDB ๋“œ๋ผ์ด๋ฒ„๋กœ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋„๋ก 4.7.7์„

@vkarpov15 66d559b19a86c70e30a8f083d03eb22566571b7e ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ์‹œ๋„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ SSL ๋ณต์ œ๋ณธ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๋ถ„/์‹œ๊ฐ„ ํ›„์— ์š”์ฒญ์ด callback()์œผ๋กœ ์ค‘์ง€๋˜๊ณ (์ข€ ๋” ์ž์„ธํ•œ ๋กœ๊น…์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค) ์˜ค๋ฅ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์–ด์ œ ๋ฐค์— 4.7.7๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŽธ์ง‘: 4.7.0์œผ๋กœ ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ ์ตœ์•…์ด์—ˆ์Šต๋‹ˆ๋‹ค(5๋ถ„ ์ด๋‚ด์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•จ). 4.5.10์„ ์‹œ๋„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@gierschv ๋…ธ๋“œ 6.9.x?

@djanowski ์•„๋‹ˆ์š”, ์—ฌ์ „ํžˆ 4.6/4.7.x LTS์— ์žˆ์Šต๋‹ˆ๋‹ค.

@djanowski ๋…ธ๋“œ 4.4.2์—์„œ๋งŒ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์˜ ๊ฐ€๋Šฅํ•œ ์ค‘๋ณต ๋ชฉ๋ก ์œ ์ง€:

  • #4638
  • #4690
  • #4901

์ฐธ๊ณ ๋กœ 4.5.10์€ ์—ฌ๊ธฐ์—์„œ ์ž˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ด๋ฉฐ ์ง€๋‚œ 5์‹œ๊ฐ„ ๋™์•ˆ ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋˜ํ•œ ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œ๋กœ ์ˆ˜์ •๋œ ๊ฒƒ์œผ๋กœ ๋ณด์ด๋Š” ๋ชจ๋“  ์ปดํ“จํ„ฐ์—์„œ #4690๊ณผ ๊ฐ™์€ ๋†’์€ CPU ์‚ฌ์šฉ๋Ÿ‰์„ ๋ณด์˜€์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ์ƒˆ๋กœ์šด ๊ฐœ๋ฐœ ์‚ฌํ•ญ์ด ์—†์Šต๋‹ˆ๊นŒ? ๋ฒ„๊ทธ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ๋” ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@sommestad ์ตœ์‹  ๋ชฝ๊ตฌ์Šค์—์„œ ์—ฌ์ „ํžˆ ์ด ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์ง€๋‚œ๋ฒˆ์— ๊ธฐ๋ณธ์ ์œผ๋กœ ์ „์ฒด ์‹œ์Šคํ…œ์„ ๋ง๊ฐ€๋œจ๋ ธ๊ธฐ ๋•Œ๋ฌธ์— ์•„์ง ์—…๊ทธ๋ ˆ์ด๋“œ๋ฅผ ๊ฐํžˆ ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค(๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ "์ผ๋ถ€" ์‹œ๊ฐ„ ํ›„์— ๋‚˜ํƒ€๋‚˜๋ฏ€๋กœ ์˜ค๋ž˜ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ ๋Š” ํ™•์ธํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค). ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค๊ณ  ๋ฏฟ์„ ๋งŒํ•œ ์ด์œ ๊ฐ€ ์žˆ๋‹ค๋ฉด ์‹œ์Šคํ…œ์˜ ๋” ๊ฒฉ๋ฆฌ๋œ ๋ถ€๋ถ„์— ์‹œ๋„ํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

ํŽธ์ง‘: ping @varunjayaraman

์ œ ์ž…์žฅ์—์„œ๋Š” ๋ช‡ ์ฃผ ์ „์— Node 6.x LTS๋กœ ์ „ํ™˜ํ•˜๊ณ  ๋งˆ์ง€๋ง‰ ๋ชฝ๊ตฌ์Šค ๋ฒ„์ „์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ–ˆ๋Š”๋ฐ ๊ทธ ์ดํ›„๋กœ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์•ฝ ๋‘ ๋‹ฌ ์ „์— Node 6.10.2, Mongoose 4.9.9๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ–ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ ๋ฌธ์ž์—ด์˜ ํ˜•์‹์€ mongodb://username:[email protected]:1234,db2.com:2345/db-name?ssl=true ์ž…๋‹ˆ๋‹ค.

console.log("fetching user...");
userCollection.findOne({_id: userId}, function(err, user){
  console.log("done"); // this never happens
  ...
});

์ฝœ๋ฐฑ์ด ์ค‘์ง€๋˜๋ฉด ๋‹ค์‹œ ์‹œ์ž‘๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋ฉด ์ž˜ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด ์ˆ˜์ง‘ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๊ธฐ๊บผ์ด ๋„์™€๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ํ‘œ์‹œ๋˜๋ฉฐ ์•„๋ž˜ ์ฝ”๋“œ๋กœ ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋น ๋ฅธ ๋ชฉ์—…/์ฝ”๋“œ ์Šคํƒ€์ผ์— ๋Œ€ํ•ด ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค).

์—ฐ๊ฒฐ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๊ธฐ ์œ„ํ•ด poolSize๋ฅผ 1๋กœ ๋‚ฎ์ถ”๊ณ  ๋‹ค์Œ ์ˆœ์„œ๋กœ ํ˜ธ์ถœ๋˜๋Š” 2๊ฐœ์˜ ์—”๋“œํฌ์ธํŠธ(์ผ๋ฐ˜/์ €์†)์— ๋Œ€ํ•œ ์š”์ฒญ์„ ํŠธ๋ฆฌ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค.

  1. ์ •์ƒ ๋์ (์ฆ‰์‹œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•จ)
  2. ๋Š๋ฆฐ ๋์ (๋Š๋ฆฐ ์ฟผ๋ฆฌ๋ฅผ ์‹œ์ž‘ํ•จ)
  3. ์ผ๋ฐ˜ ์—”๋“œํฌ์ธํŠธ(2์—์„œ ์‚ฌ์šฉ ์ค‘์ด๋ฏ€๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—ฐ๊ฒฐ์„ ๊ธฐ๋‹ค๋ฆผ)
  4. ์ผ๋ฐ˜ ์—”๋“œํฌ์ธํŠธ(2์™€ 3์ด MongoError / ์—ฐ๊ฒฐ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ์ดˆ๋ž˜ํ•œ ๊ฒฝ์šฐ 1๋ถ„ ํ›„์— ํŠธ๋ฆฌ๊ฑฐ๋จ)

๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ์žฌํ˜„:

// Require modules
const mongoose = require('mongoose');
const express = require('express');
const request = require('request');
const parseJson = require('body-parser').json();

// Use native Promises in Mongoose
mongoose.Promise = Promise;

// Create the test schema
const testSchema = new mongoose.Schema({
  name: {
    type: String,
    trim: true,
    default: 'test'
  }
});

// Create the mongoose model
mongoose.model('Test', testSchema, 'test');

// Create some test data
mongoose.model('Test').create([
  {name: 'test1'},
  {name: 'test2'},
  {name: 'test3'},
  {name: 'test4'},
  {name: 'test5'}
]);

// Create the Express based app
const app = express();

// Create the express router
const router = express.Router();

// Create a normal route
router.route('/normal').get(parseJson, function (req, res, next) {
  mongoose.model('Test').find({}).then(
    function (data) {
      res.status(200).json(data);
    }
  ).catch(
    function (err) {
      res.status(400).json(err);
    }
  );
});

// Create up a slow route
router.route('/slow').get(parseJson, function (req, res, next) {
  mongoose.model('Test').find({$where: 'sleep(10000) || true'}).then(
    function (data) {
      res.status(200).json(data);
    }
  ).catch(
    function (err) {
      res.status(400).json(err);
    }
  );
});

// Add middleware to console log every request
var requestNumber = 1;
app.use(function (req, res, next) {
  console.log('Request ' + requestNumber, req.method, req.url);
  requestNumber++;
  next();
});

// Use the router
app.use('/', router);

// Listen for requests
app.listen(4000, function () {
  console.log('Server listening on port 4000');
});

// Catch any uncaught exceptions
process.on('uncaughtException', function (err) {
  console.log('Uncaught exception', err);
});

// Catch any unhandled rejections
process.on('unhandledRejection', function (reason) {
  console.error('Unhandled Rejection', reason);
});

// Database connection options
const connectionOpts = {
  // Use the new connection logic
  useMongoClient: true,

  // Do not auto reconnect (the Node code will auto reconnect)
  autoReconnect: false,

  // Use a poolsize of 1 to simulate a timeout using multiple request to slow and normal endpoints
  poolSize: 1
};

// Connection method with retry
const connectWithRetry = function () {
  // Check if we still need to connect
  if (mongoose.connection.readyState !== mongoose.Connection.STATES.connected) {
    // Connect
    return mongoose.connect('mongodb://localhost:27017/test', connectionOpts).catch(
      function (err) {
        console.log('Can not connect to mongo', err);
      }
    );
  }
};

// Helper function to execute a request to the normal endpoint
const doRequestNormal = function () {
  request({
    url: 'http://localhost:4000/normal',
    json: true,
    timeout: 60000
  }, function (error, response, body) {
    if (error) {
      console.log('Error on normal request', error, response);
    }
    console.log('Performed normal request, body:', body);
  });
};

// Helper function to execute a request to the normal endpoint
const doRequestSlow = function () {
  request({
    url: 'http://localhost:4000/slow',
    json: true,
    timeout: 60000
  }, function (error, response, body) {
    if (error) {
      console.log('Error on slow request', error, response);
    }
    console.log('Performed slow request', body);
  });
};

// Helper function to simulate requests
const doRequests = function () {
  doRequestNormal();
  doRequestSlow();
  doRequestNormal();

  setTimeout(function () {
    console.log('Do normal request after 1 minute');
    doRequestNormal();
  }, 60000);
};

// Connecting event
mongoose.connection.on('connecting', function () {
  console.log('Connecting to database...');
});

// Connected event
mongoose.connection.on('connected', function () {
  console.log('Database is connected, start requesting...');
  doRequests();
});

// Timeout event
mongoose.connection.on('timeout', function (err) {
  console.log('Database timeout error', err);
});

// Error event
mongoose.connection.on('error', function (err) {
  console.log('Database connection error', err);
});

// Disconnected event
mongoose.connection.on('disconnected', function () {
  console.error('Database got disconnected, reconnecting in 5 sec...');

  // Reconnect in 5 seconds
  setTimeout(connectWithRetry, 5000);
});

// Connect to the database with retry
connectWithRetry();

// Log the connection state every 10 seconds
setInterval(function () {
  console.log('Mongoose connection readystate is', mongoose.connection.readyState);
}, 10000);

์ฝ˜์†” ์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Connecting to database...
Server listening on port 4000
Database is connected, start requesting...
Request 1 GET /normal
Request 2 GET /slow
Request 3 GET /normal
Performed normal request, body: [ { _id: '597f8c6f41bf2e119594ba1a', __v: 0, name: 'test1' },
  { _id: '597f8c6f41bf2e119594ba1b', __v: 0, name: 'test2' },
  { _id: '597f8c6f41bf2e119594ba1c', __v: 0, name: 'test3' },
  { _id: '597f8c6f41bf2e119594ba1d', __v: 0, name: 'test4' },
  { _id: '597f8c6f41bf2e119594ba1e', __v: 0, name: 'test5' } ]
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Performed slow request { name: 'MongoError',
  message: 'connection 0 to localhost:27017 timed out' }
Performed normal request, body: { name: 'MongoError',
  message: 'connection 0 to localhost:27017 timed out' }
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Do normal request after 1 minute
Request 4 GET /normal
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Error on normal request { Error: ESOCKETTIMEDOUT
    at ClientRequest.<anonymous> (/Users/adriaanmeuris/Documents/Projecten/Mongoose timeout/node_modules/request/request.js:819:19)
    at ClientRequest.g (events.js:291:16)
    at emitNone (events.js:86:13)
    at ClientRequest.emit (events.js:185:7)
    at Socket.emitTimeout (_http_client.js:620:10)
    at Socket.g (events.js:291:16)
    at emitNone (events.js:86:13)
    at Socket.emit (events.js:185:7)
    at Socket._onTimeout (net.js:339:8)
    at ontimeout (timers.js:365:14)
    at tryOnTimeout (timers.js:237:5)
    at Timer.listOnTimeout (timers.js:207:5) code: 'ESOCKETTIMEDOUT', connect: false } undefined
Performed normal request, body: undefined
Mongoose connection readystate is 1
Mongoose connection readystate is 1

10์ดˆ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ readyState๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์—ฐ๊ฒฐ์ด ์—ฌ์ „ํžˆ ํ™œ์„ฑ ์ƒํƒœ์ž„์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. Mongoose ์˜ค๋ฅ˜/์‹œ๊ฐ„ ์ดˆ๊ณผ ์ด๋ฒคํŠธ๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š๊ณ  ์š”์ฒญ 4์˜ ์ฝœ๋ฐฑ์ด ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์š”์ฒญ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ 60์ดˆ ํ›„์— ์‹œ๊ฐ„ ์ดˆ๊ณผ๋จ). http://localhost :4000/slow ๋ฐ ๋‹ค์Œ http://localhost :4000/normal์„ ๋ฐฉ๋ฌธํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” https://team.goodeggs.com/reconnecting-to-mongodb-when-mongoose-connect-fails-at-startup-83ca8496ca02 ๊ธฐ๋ฐ˜์˜ ์ž๋™ ์žฌ์—ฐ๊ฒฐ ๋กœ์ง์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€๋งŒ, mongo๊ฐ€ ์—ฐ๊ฒฐ์„ ๋Š์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์€ ๊ฒฐ์ฝ” ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ์ผ๋ถ€ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ์— ์ฃผ์„์„ ๋‹ฌ ๋•Œ ์žฌํ˜„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค(๊ธฐ๋ณธ์ ์œผ๋กœ ๋นˆ ์ปฌ๋ ‰์…˜์„ ์ฟผ๋ฆฌํ•จ)

๊ฐ€๋Šฅํ•œ ๊ด€๋ จ ๋ฌธ์ œ:

  • #4789
  • #4660

๋„์›€์„ ์ฃผ์‹œ๋ฉด ๋Œ€๋‹จํžˆ ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ mongoose๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  node-mongodb-native์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋„๋ก ์œ„์˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋Š” ์ง€๊ธˆ ๋งค์šฐ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ ์„ค์ • ๋ฐ ์š”์ฒญ์€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

  1. ์ •์ƒ ๋์ (์ฆ‰์‹œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•จ)
  2. ๋Š๋ฆฐ ๋์ (๋Š๋ฆฐ ์ฟผ๋ฆฌ๋ฅผ ์‹œ์ž‘ํ•จ)
  3. ์ผ๋ฐ˜ ์—”๋“œํฌ์ธํŠธ(2์—์„œ ์‚ฌ์šฉ ์ค‘์ด๋ฏ€๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—ฐ๊ฒฐ์„ ๊ธฐ๋‹ค๋ฆผ)
  4. ์ผ๋ฐ˜ ๋์ (1๋ถ„ ํ›„์— ํŠธ๋ฆฌ๊ฑฐ๋จ)

์•”ํ˜ธ:

// Require modules
const MongoClient = require('mongodb').MongoClient;
const Server = require('mongodb').Server;
const express = require('express');
const request = require('request');
const parseJson = require('body-parser').json();

// The db reference
var db;

// Function to insert test data
function insertTestData() {
  return new Promise(function (resolve, reject) {
    // Get the test collection
    var test = db.collection('test');

    // Insert some documents
    test.insertMany([
      {name: 'test1'},
      {name: 'test2'},
      {name: 'test3'},
      {name: 'test4'},
      {name: 'test5'}
    ], function (err, result) {
      if (err) {
        reject(err);
      } else {
        resolve();
      }
    });
  });
}

// Create the Express based app
const app = express();

// Create the express router
const router = express.Router();

// Create a normal route
router.route('/normal').get(parseJson, function (req, res, next) {
  // Get the documents collection
  var collection = db.collection('test');

  // Find some documents
  collection.find({}).toArray(function (err, data) {
    if (err) {
      res.status(400).json(err);
    } else {
      res.status(200).json(data);
    }
  });
});

// Create up a slow route
router.route('/slow').get(parseJson, function (req, res, next) {
  // Get the documents collection
  var collection = db.collection('test');

  // Find some documents
  collection.find({$where: 'sleep(10000) || true'}).toArray(function (err, data) {
    if (err) {
      res.status(400).json(err);
    } else {
      res.status(200).json(data);
    }
  });
});

// Add middleware to console log every request
var requestNumber = 1;
app.use(function (req, res, next) {
  console.log('Request ' + requestNumber, req.method, req.url);
  requestNumber++;
  next();
});

// Use the router
app.use('/', router);

// Listen for requests
app.listen(4000, function () {
  console.log('Server listening on port 4000');
});

// Catch any uncaught exceptions
process.on('uncaughtException', function (err) {
  console.log('Uncaught exception', err);
});

// Catch any unhandled rejections
process.on('unhandledRejection', function (reason) {
  console.error('Unhandled Rejection', reason);
});

// Database connection options
const connectionOpts = {
  // Do not auto reconnect (the Node code will auto reconnect)
  autoReconnect: false,

  // Use a poolsize of 1 to simulate a timeout using multiple request to slow and normal endpoints
  poolSize: 1
};

// Connection method with retry
const connectWithRetry = function () {

  return MongoClient.connect('mongodb://localhost:27017/test', connectionOpts).then(
    function (database) {
      db = database;
      setupEvents();
      console.log('Connected to mongo');
    }
  ).catch(
    function (err) {
      console.log('Can not connect to mongo', err);
      return err;
    }
  );
};

// Helper function to execute a request to the normal endpoint
const doRequestNormal = function () {
  request({
    url: 'http://localhost:4000/normal',
    json: true,
    timeout: 60000
  }, function (error, response, body) {
    if (error) {
      console.log('Error on normal request', error, response);
    }
    console.log('Performed normal request, body:', body);
  });
};

// Helper function to execute a request to the normal endpoint
const doRequestSlow = function () {
  request({
    url: 'http://localhost:4000/slow',
    json: true,
    timeout: 60000
  }, function (error, response, body) {
    if (error) {
      console.log('Error on slow request', error, response);
    }
    console.log('Performed slow request', body);
  });
};

// Helper function to simulate requests
const doRequests = function () {
  doRequestNormal();
  doRequestSlow();
  doRequestNormal();

  setTimeout(function () {
    console.log('Do normal request after 1 minute');
    doRequestNormal();
  }, 60000);
};

// Helper function to setup mongo events
function setupEvents() {
// Connecting event
  db.on('connecting', function () {
    console.log('Connecting to database...');
  });

// Connected event
  db.on('connected', function () {
    console.log('Database is connected, start requesting...');
  });

// Timeout event
  db.on('timeout', function (err) {
    console.log('Database timeout error', err);
  });

// Error event
  db.on('error', function (err) {
    console.log('Database connection error', err);
  });

// Disconnected event
  db.on('close', function () {
    console.error('Database got disconnected, reconnecting in 5 sec...');

    // Reconnect in 5 seconds
    setTimeout(connectWithRetry, 5000);
  });
}

// Connect to the database with retry
connectWithRetry().then(
  function () {
    return insertTestData();
  }
).then(
  function () {
    doRequests();
  }
);

์ฝ˜์†” ์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Server listening on port 4000
Connected to mongo
Request 1 GET /normal
Request 2 GET /slow
Request 3 GET /normal
Performed normal request, body: [ { _id: '598207c16caf9224cf3b8897', name: 'test1' },
  { _id: '598207c16caf9224cf3b8898', name: 'test2' },
  { _id: '598207c16caf9224cf3b8899', name: 'test3' },
  { _id: '598207c16caf9224cf3b889a', name: 'test4' },
  { _id: '598207c16caf9224cf3b889b', name: 'test5' } ]
Performed slow request [ { _id: '598207c16caf9224cf3b8897', name: 'test1' },
  { _id: '598207c16caf9224cf3b8898', name: 'test2' },
  { _id: '598207c16caf9224cf3b8899', name: 'test3' },
  { _id: '598207c16caf9224cf3b889a', name: 'test4' },
  { _id: '598207c16caf9224cf3b889b', name: 'test5' } ]
Performed normal request, body: [ { _id: '598207c16caf9224cf3b8897', name: 'test1' },
  { _id: '598207c16caf9224cf3b8898', name: 'test2' },
  { _id: '598207c16caf9224cf3b8899', name: 'test3' },
  { _id: '598207c16caf9224cf3b889a', name: 'test4' },
  { _id: '598207c16caf9224cf3b889b', name: 'test5' } ]
Do normal request after 1 minute
Request 4 GET /normal
Performed normal request, body: [ { _id: '598207c16caf9224cf3b8897', name: 'test1' },
  { _id: '598207c16caf9224cf3b8898', name: 'test2' },
  { _id: '598207c16caf9224cf3b8899', name: 'test3' },
  { _id: '598207c16caf9224cf3b889a', name: 'test4' },
  { _id: '598207c16caf9224cf3b889b', name: 'test5' } ]

Mongo ์˜ค๋ฅ˜/์‹œ๊ฐ„ ์ดˆ๊ณผ ์ด๋ฒคํŠธ๋Š” ์ด์ „ ์Šคํฌ๋ฆฝํŠธ์™€ ๊ฐ™์ด ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š์ง€๋งŒ ์š”์ฒญ 2 ๋ฐ 3์€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ•ด๊ฒฐ๋˜๊ณ  ์š”์ฒญ 4์˜ ์ฝœ๋ฐฑ๋„ ํŠธ๋ฆฌ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. Mongoose๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ์™€ ๋Œ€์กฐ๋ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด Mongoose ๋Œ€ Mongo ๋ฌธ์ œ์ธ์ง€ ์—ฌ๋ถ€๋ฅผ ๋ฐฐ์ œํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ์Šคํฌ๋ฆฝํŠธ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋น„๊ตํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์–ด์ฉŒ๋ฉด @vkarpov15 ๊ฐ€ ์ด๊ฒƒ์— ๋Œ€ํ•ด ์ฐจ์ž„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ฐ์‚ฌ ํ•ด์š”!

@adriaanmeuris ์ด์ƒํ•ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์–ป์€ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

$ node gh-4513.js 
Connecting to database...
Server listening on port 4000
Database is connected, start requesting...
Request 1 GET /normal
Request 2 GET /slow
Request 3 GET /normal
Performed normal request, body: [ { _id: '5998e4a79bb81d37ac4b1a26', __v: 0, name: 'test1' },
  { _id: '5998e4a79bb81d37ac4b1a27', __v: 0, name: 'test2' },
  { _id: '5998e4a79bb81d37ac4b1a28', __v: 0, name: 'test3' },
  { _id: '5998e4a79bb81d37ac4b1a29', __v: 0, name: 'test4' },
  { _id: '5998e4a79bb81d37ac4b1a2a', __v: 0, name: 'test5' } ]
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Mongoose connection readystate is 1
Performed slow request [ { _id: '5998e4a79bb81d37ac4b1a26', __v: 0, name: 'test1' },
  { _id: '5998e4a79bb81d37ac4b1a27', __v: 0, name: 'test2' },
  { _id: '5998e4a79bb81d37ac4b1a28', __v: 0, name: 'test3' },
  { _id: '5998e4a79bb81d37ac4b1a29', __v: 0, name: 'test4' },
  { _id: '5998e4a79bb81d37ac4b1a2a', __v: 0, name: 'test5' } ]
Performed normal request, body: [ { _id: '5998e4a79bb81d37ac4b1a26', __v: 0, name: 'test1' },
  { _id: '5998e4a79bb81d37ac4b1a27', __v: 0, name: 'test2' },
  { _id: '5998e4a79bb81d37ac4b1a28', __v: 0, name: 'test3' },
  { _id: '5998e4a79bb81d37ac4b1a29', __v: 0, name: 'test4' },
  { _id: '5998e4a79bb81d37ac4b1a2a', __v: 0, name: 'test5' } ]
Mongoose connection readystate is 1
Do normal request after 1 minute
Request 4 GET /normal
Performed normal request, body: [ { _id: '5998e4a79bb81d37ac4b1a26', __v: 0, name: 'test1' },
  { _id: '5998e4a79bb81d37ac4b1a27', __v: 0, name: 'test2' },
  { _id: '5998e4a79bb81d37ac4b1a28', __v: 0, name: 'test3' },
  { _id: '5998e4a79bb81d37ac4b1a29', __v: 0, name: 'test4' },
  { _id: '5998e4a79bb81d37ac4b1a2a', __v: 0, name: 'test5' } ]
Mongoose connection readystate is 1
Mongoose connection readystate is 1
^C
$ 

๋ชฝ๊ตฌ์Šค๋Š” ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. mongodb, node ๋ฐ mongoose์˜ ๋ฒ„์ „์„ ๋ช…ํ™•ํžˆ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

ํ…Œ์ŠคํŠธํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ์‹ค์ œ๋กœ Mongoose๋Š” ํ•ญ์ƒ ์—ฐ๊ฒฐ๋œ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜์ง€๋งŒ ์ฝœ๋ฐฑ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(Express๋กœ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์„ ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋จ).

๋‚˜๋Š” ๋‹ค์Œ๊ณผ ํ•จ๊ป˜ ํ…Œ์ŠคํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๋…ธ๋“œ 6.8.1
  • ๋ชฝ๊ณ DB 2.2.30
  • ๋ชฝ๊ตฌ์Šค 4.11.5

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๋…ธ๋“œ 6.8.1
  • ๋ชฝ๊ณ DB 2.2.31
  • ๋ชฝ๊ตฌ์Šค 4.11.7

๋‚ด๊ฐ€ ๊ฒŒ์‹œํ•œ ์ฒซ ๋ฒˆ์งธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ์ปฌ์—์„œ ์—ฌ์ „ํžˆ ๋ฌธ์ œ๋ฅผ ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Mongo ์—ฐ๊ฒฐ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋œ ๊ฒฝ์šฐ์—๋งŒ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ๋‹ค์Œ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

mongoose.model('Test').find({$where: 'sleep(10000) || true'})

(์ด ์ž‘์—…์ด ๋ชจ๋“  ์ปดํ“จํ„ฐ์—์„œ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ์œ ๋ฐœํ•˜๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์žฌํ˜„์„ ์œ„ํ•ด ์ด ์ฟผ๋ฆฌ๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.)

mongoose 4.10.4๋กœ ์—…๋ฐ์ดํŠธํ•œ ํ›„ ๋” ์ด์ƒ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋ฌธ์ œ๋ฅผ ๊ฒฝํ—˜ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ๋‹ค์‹œ ๋ฐœ์ƒํ•˜๋Š” ์ง•ํ›„ ์—†์ด ๋ช‡ ์ฃผ ๋™์•ˆ ๋งŽ์€ ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์•ฝ๊ฐ„ ์ด์ƒํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ๐Ÿค”

๊ทธ๋Ÿฌ๋‚˜ ์ด์ „์— @adriaanmeuris ์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ œ๋ฅผ

๋…ธ๋“œ 8์„ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋Š” ์—ฌ์ „ํžˆ ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

@adriaanmeuris ์˜ ์Šคํฌ๋ฆฝํŠธ๋กœ๋Š” ๊ทธ๊ฒƒ์„ ์žฌํ˜„ํ•  ์ˆ˜ ์—†์—ˆ์ง€๋งŒ , ๋‹ค์Œ์€ ์ €๋ฅผ ์œ„ํ•ด ๋งค๋ฒˆ ๊ทธ๊ฒƒ์„ ์žฌํ˜„ํ•˜๋Š” ์ˆ˜์ •๋œ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค:

๋ฒค๋””ํŠธ๋ฆฌ/๋ชฝ๊ตฌ์Šค ์ด์Šˆ-4513

@bendytree ์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์Šคํฌ๋ฆฝํŠธ๋กœ ์ €๋„ ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

7) Database connecting...
49) Database connected...
49) Dropping...
57) Creating...
156) FastQuery-A: starting...
166) FastQuery-A: success: 1
1158) SlowQuery: starting...
2158) FastQuery-B: starting...
362165) SlowQuery: failed: MongoError: connection 0 to localhost:27017 timed out
362167) FastQuery-B: failed: MongoError: connection 0 to localhost:27017 timed out
605159) FastQuery-C: starting...
1210149) Giving Up...

๋ณธ์งˆ์ ์œผ๋กœ ๋‚ด ์Šคํฌ๋ฆฝํŠธ์™€ ๊ฐ™์ง€๋งŒ ์‹œ๊ฐ„ ์ดˆ๊ณผ ๊ธฐ๊ฐ„์ด ๋” ๊น๋‹ˆ๋‹ค. ๋ชจ๋“  ์‚ฌ๋žŒ์ด ๋‚ด ์Šคํฌ๋ฆฝํŠธ(10์ดˆ ์ ˆ์ „ ์‚ฌ์šฉ)๋กœ ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฏ€๋กœ ์„ค์ •์— ๋”ฐ๋ผ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ๋กœ์ปฌ์—์„œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋Š” ๋ฐ ๋” ๋งŽ๊ฑฐ๋‚˜ ์ ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋ฉ๋‹ˆ๋‹ค.

@vkarpov15 ์ด ์—…๋ฐ์ดํŠธ๋œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” mongoose 4.8.11๋กœ ํ…Œ์ŠคํŠธ ๋ฐ ์žฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

@bendytree ๋กœ ์žฌํ˜„ํ•  ์ˆ˜ socketTimeoutMS ๋„ˆ๋ฌด ๋‚ฎ์€ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. NS

362591) SlowQuery: failed: MongoError: connection 0 to localhost:27017 timed out
362591) FastQuery-B: failed: MongoError: connection 0 to localhost:27017 timed out

๋ฉ”์‹œ์ง€๋Š” mongodb ๋“œ๋ผ์ด๋ฒ„์˜ ์†Œ์ผ“ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. mongodb ๋“œ๋ผ์ด๋ฒ„๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ 30์ดˆ ํ›„์— ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์ง€๋งŒ OS์—๋Š” ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š” ์†Œ์ผ“ ์‹œ๊ฐ„ ์ดˆ๊ณผ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์ผ๋ฐ˜์ ์œผ๋กœ 15์ดˆ ์ด์ƒ ๊ฑธ๋ฆฌ๋Š” ์ฟผ๋ฆฌ๋Š” ํ”ผํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ socketTimeoutMS ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ mongodb์˜ ์†Œ์ผ“ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

mongoose.connect(DB_URL, {
  useMongoClient: true,
  autoReconnect: false,
  poolSize: 1,
  socketTimeoutMS: 0
}).catch((err)=>{ log('Connect failed', err); });

ํ•ด๋‹น ์˜ต์…˜์„ 0์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‚ด ์ปดํ“จํ„ฐ์—์„œ ๊ฑฐ์˜ ์„ฑ๊ณตํ•˜๊ณ  10๋ถ„ ์ฟผ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ ์ฃฝ์ง€๋งŒ ์ฝœ๋ฐฑ์€ ๊ณ„์†๋ฉ๋‹ˆ๋‹ค.

$ node gh-4513.js 
9) Database connecting...
43) Database connected...
43) Dropping...
53) Creating...
177) FastQuery-A: starting...
189) FastQuery-A: success: 1
1174) SlowQuery: starting...
2174) FastQuery-B: starting...
601181) SlowQuery: failed: MongoError: Interrupted by the host
601182) FastQuery-B: success: 1
605173) FastQuery-C: starting...
605174) FastQuery-C: success: 1

๊ทธ๋Ÿฌ๋‚˜ ํ›„์† ์ฟผ๋ฆฌ๋Š” ์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์–ด๋Š ์ชฝ์ด๋“ , ์ด ๊ฒฝ์šฐ ๋ชฝ๊ตฌ์Šค๋Š” ์‹œ๊ฐ„ ์ดˆ๊ณผ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์•ผ ํ•˜๋ฏ€๋กœ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด connectTimeoutMS(๊ธฐ๋ณธ๊ฐ’ 30000ms)์™€ socketTimeoutMS(๊ธฐ๋ณธ๊ฐ’ 360000ms)๋ฅผ ํ˜ผ๋™ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

socketTimeoutMS๋ฅผ ๋“œ๋ผ์ด๋ฒ„๋ฅผ ํ†ตํ•ด ์‹คํ–‰๋˜๋Š” ๊ฐ€์žฅ ๋Š๋ฆฐ ์ž‘์—… ๊ธธ์ด์˜ 2~3๋ฐฐ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. socketTimeoutMS๋ฅผ 0์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ์‹ค์ œ๋กœ ์šด์˜ ์ฒด์ œ ๊ธฐ๋ณธ ์†Œ์ผ“ ์‹œ๊ฐ„ ์ดˆ๊ณผ ๊ฐ’์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค(์ž์„ธํ•œ ์ •๋ณด๋Š” http://mongodb.github.io/ ์ฐธ์กฐ). node-mongodb-native/2.2/reference/faq/).

๋”ฐ๋ผ์„œ ์ด ์งˆ๋ฌธ์ด ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ œํ•œ(๊ณ ์ • ๋˜๋Š” ๊ธฐ๋ณธ OS ์‹œ๊ฐ„ ์ดˆ๊ณผ)์— ๋„๋‹ฌํ–ˆ์„ ๋•Œ ์ด๋Ÿฌํ•œ ์ฝœ๋ฐฑ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@vkarpov15 with [email protected] , ์ด์ œ ์‹œ๊ฐ„ ์ดˆ๊ณผ ์ด๋ฒคํŠธ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ์ „ํžˆ ์ด ์ฝœ๋ฐฑ ๋ฌธ์ œ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค( @bendytree ์˜ ์›๋ž˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋” ๋น ๋ฅธ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด LONG_QUERY_DURATION_IN_MS๋ฅผ 2000์œผ๋กœ, socketTimeoutMS๋ฅผ 1000์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Œ).

๋” ๋งŽ์€ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ–ˆ์œผ๋ฉฐ Mongoose ์—†์ด๋„ ์ด๊ฒƒ์ด ์žฌํ˜„๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. http://mongodb.github.io/node-mongodb-native/2.2/reference/faq/ ๋ฅผ ์ฝ์„ ๋•Œ ๋‹ค์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. Closing the socket forces a reconnect of the driverโ€™s connection pool and introduces latency to any other operations which are queued up

mongoose.connection.readyState ๋Š” ํ•ญ์ƒ 1์ด์ง€๋งŒ autoReconnect ๋ฅผ true ์„ค์ •ํ•˜๋ ค๊ณ  ์‹œ๋„ํ–ˆ์œผ๋ฉฐ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

8) Database connecting...
47) Database connected...
48) Dropping...
73) Creating...
123) FastQuery-A: starting...
129) FastQuery-A: success: 1
1122) SlowQuery: starting...
2126) FastQuery-B: starting...
3130) Database timeout...
3133) SlowQuery: failed: MongoError: connection 0 to localhost:27017 timed out
3133) FastQuery-B: failed: MongoError: connection 0 to localhost:27017 timed out
6063) Database timeout...
7122) FastQuery-C: starting...
7125) FastQuery-C: success: 1
8129) Database timeout...
11070) Database timeout...
13073) Database timeout...

๋”ฐ๋ผ์„œ autoReconnect๊ฐ€ true๋กœ ์„ค์ •๋œ ์ƒํƒœ์—์„œ ์ฝœ๋ฐฑ์ด ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿ‘

์ด ๊ธฐ์‚ฌ๋ฅผ ๋” ์ฝ์œผ๋ฉด: http://mongodb.github.io/node-mongodb-native/2.0/tutorials/connection_failures/ , ํƒ€์ž„์•„์›ƒ ํ›„์— ์ฝœ๋ฐฑ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ์ž‘์—…์ด ์„œ๋ฒ„๊ฐ€ ๋‹ค์‹œ ์—ฐ๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ๋ฒ„ํผ๋ง๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ autoReconnect ๋ฅผ false autoReconnect ๋‹ค์‹œ ์„ค์ •ํ•˜๋ ค๊ณ  ์‹œ๋„ํ–ˆ์ง€๋งŒ bufferMaxEntries ๋ฅผ 0 ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ต๋‹ˆ๋‹ค.

8) Database connecting...
51) Database connected...
51) Dropping...
58) Creating...
112) FastQuery-A: starting...
116) FastQuery-A: success: 1
1115) SlowQuery: starting...
2115) FastQuery-B: starting...
3123) Database timeout...
3123) SlowQuery: failed: MongoError: connection 0 to localhost:27017 timed out
3123) FastQuery-B: failed: MongoError: connection 0 to localhost:27017 timed out
7115) FastQuery-C: starting...
7117) FastQuery-C: failed: MongoError: no connection available for operation and number of stored operation > 0

์ด๋Š” @bendytree ์Šคํฌ๋ฆฝํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ๋ฒ„์ „์—์„œ ์ฝœ๋ฐฑ์ด ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š์€ ์ด์œ ๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

@vkarpov15 ์ด์ œ 2๊ฐ€์ง€ ์งˆ๋ฌธ์ด ๋‚จ์Šต๋‹ˆ๋‹ค.

  • ์—ฐ๊ฒฐ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ์ด์œ (์—ฐ๊ฒฐ์ด ๋Š๊ธด ์ด๋ฒคํŠธ๊ฐ€ ํ‘œ์‹œ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋จ)
  • ์‹œ๊ฐ„ ์ดˆ๊ณผ ์ด๋ฒคํŠธ ์ด๋ฒคํŠธ๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ์—…๋ฐ์ดํŠธ ๋œ ์Šคํฌ๋ฆฝํŠธ (@bendytree์„ ๊ธฐ๋ฐ˜์˜ ์Šคํฌ๋ฆฝํŠธ, [email protected] ๋ฐ [email protected] ํ…Œ์ŠคํŠธ๋Š”)์ž…๋‹ˆ๋‹ค :

const LONG_QUERY_DURATION_IN_MS = 2000;
const DB_URL = 'mongodb://localhost:27017/test_mongoose_callbacks';

const mongoose = require('mongoose');
mongoose.Promise = Promise;

var startTime = new Date().getTime();
var log = (msg) => {
  var seconds = Math.round(new Date().getTime() - startTime);
  console.log(seconds+") "+msg);
};

var Model = mongoose.model('Test', new mongoose.Schema({
  name: { type: String, trim: true, default: 'test' }
}), 'test');

mongoose.connection.on('connecting',   () => { log('Database connecting...'); });
mongoose.connection.on('timeout',      () => { log('Database timeout...'); });
mongoose.connection.on('error',        () => { log('Database error...'); });
mongoose.connection.on('disconnected', () => { log('Database disconnected...'); });

const doRequest = function (title, slow) {
  var logRequest = (msg) => { log(title+": "+msg); };

  logRequest("starting...");
  var filter = slow ? {$where: 'sleep('+LONG_QUERY_DURATION_IN_MS+') || true'} : {};
  Model.count(filter).exec((err, count) => {
    logRequest(err ? "failed: "+err : "success: "+count);
  });
};

mongoose.connection.on('connected', () => {
  log("Database connected...");
 log("Dropping...");
 mongoose.connection.db.dropDatabase(function(){
   log("Creating...");
   Model.create([ {name: 'test1'} ], function(){
      setTimeout(() => { doRequest("FastQuery-A", false); }, 0);
      setTimeout(() => { doRequest("SlowQuery", true);  }, 1000);
      setTimeout(() => { doRequest("FastQuery-B", false); }, 2000);
      setTimeout(() => { doRequest("FastQuery-C", false); }, LONG_QUERY_DURATION_IN_MS+5000);
      setTimeout(() => { log("Giving Up..."); }, LONG_QUERY_DURATION_IN_MS+30000);
    });
  });
});

mongoose.connect(DB_URL, {
  useMongoClient: true,
  autoReconnect: true,
  //bufferMaxEntries: 0, // Uncomment to disable buffering operations 
  poolSize: 1,
  socketTimeoutMS: 1000
}).catch((err)=>{ log('Connect failed', err); });

setInterval(()=>{
  if (mongoose.connection.readyState === 1) return;
  log('Mongoose.readystate = ', mongoose.connection.readyState);
}, 1000);

๋„ค ๋งž์•„์š”. ์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์— ๋Œ€ํ•ด ๋” ์ž˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. timeout ์ด๋ฒคํŠธ๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ ์ด ๊ฒฝ์šฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ์—๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

'disconnected'๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” 'timeout'์ด ์ „์ฒด ํ’€์ด ์•„๋‹ˆ๋ผ ํ•˜๋‚˜์˜ ์†Œ์ผ“์ด ์‹œ๊ฐ„ ์ดˆ๊ณผ๋˜์—ˆ์Œ์„ ์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. Mongoose๋Š” ํƒ€์ž„์•„์›ƒ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ํ’€์˜ ์†Œ์ผ“์ด ๋ช‡ ๊ฐœ๋‚˜ ์•„์ง ์‚ด์•„ ์žˆ๋Š”์ง€ ์•Œ์•„์•ผ ํ•˜๋ฉฐ, ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋‚ด๊ธฐ ์œ„ํ•ด ๋” ๋งŽ์€ ์กฐ์‚ฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์‹œ๊ฐ„ ์ดˆ๊ณผ ์ด๋ฒคํŠธ๊ฐ€ ๊ณ„์† ์žฌ๋ฐœํ•˜๋Š” ์ด์œ ๋ฅผ ๋” ์กฐ์‚ฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋‹ค๋ ค ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค :+1:

๋‚˜๋Š” ์ด๊ฒƒ์„ mongodb ๋“œ๋ผ์ด๋ฒ„์˜ ๋ช‡ ๊ฐ€์ง€ ๋ฒ„๊ทธ๋กœ ์ถ”์ ํ–ˆ์Šต๋‹ˆ๋‹ค: https://github.com/mongodb-js/mongodb-core/pull/215 . ๋ชฝ๊ตฌ์Šค์— ํŒจ์น˜๋ฅผ ์ ์šฉํ•˜๊ธฐ ์ „์— ๋ณ‘ํ•ฉ๋˜๊ณ  ๋ฐฐํฌ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด ์ž์‹ ์˜ ํ…Œ์ŠคํŠธ์—์„œ @vkarpov15 ๋‚˜๋Š” mongoose.connection.readyState ์ ˆ๋Œ€ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ฒฝํ—˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ฐ™์€ ๋ฌธ์ œ์ž…๋‹ˆ๊นŒ?

@r3wt ๊ทธ ๋ฌธ์ œ๋Š” 4.11.13์—์„œ ์ˆ˜์ •๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

@ vkarpov15 ๋‚ด ๊ฒŒ์‹œ๋ฌผ ๋‹น์‹œ 4.11.11์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌํ•œ ๋ช…๋ฐฑํ•œ ๋‚˜์œ ํ–‰๋™์ด ๊ทธ๋Ÿฌํ•œ ์ฃผ๋ชฉํ• ๋งŒํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ”„๋กœ๋•์…˜์— ๋ชฐ๋ž˜ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ๋‚™๋‹ดํ•ฉ๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ๋” ๋‚˜์€ ํ…Œ์ŠคํŠธ ์ ˆ์ฐจ๊ฐ€ ํ•„์š”ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. (๋‚˜๋Š” ๋ฌด๋ก€ํ•˜๊ฒŒ ํ•˜๋ ค๊ณ  ํ•˜์ง€ ์•Š๋Š”๋‹ค, ๋‚˜๋Š” ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์–ผ๋งˆ๋‚˜ ์–ด๋ ค์šด์ง€ ์•Œ๊ณ  ์žˆ๋‹ค. ๋•Œ๋•Œ๋กœ ๊ทธ๊ฒƒ์€ ์งœ์ฆ๋‚œ๋‹ค)

@ vkarpov15 ์ €๋Š” ๋ชฝ๊ตฌ์Šค ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๊ฐœ๋ฐœ ์ค‘์ž…๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ์ด ์ค€๋น„๋  ๋•Œ๊นŒ์ง€ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ฐจ๋‹จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์—ฐ๊ฒฐ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค(์ด์œ ๋กœ ์ธํ•ด). ์—ฐ๊ฒฐ์ด ์ค€๋น„๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

function ready(){
    console.log('ready()');
    return new Promise((resolve,reject)=>{
        var _int = setInterval(()=>{
            if(mongoose.connection.readyState == 1 || forceReady){
                clearInterval(_int);
                console.log('mongoose connected ready().resolve()')
                resolve();
            }
        },200);
    })
}

๋‚˜๋Š” ๋˜ํ•œ mongoose.connnection.on('connected') ๋ฅผ ํ†ตํ•ด ๋“ฃ๊ธฐ๋ฅผ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์•„์•„ ๊ทธ๊ฒƒ๋„ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋นˆ ์„ค์น˜์—์„œ๋Š” ์ž˜ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค๋ฅธ mongoose ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ฐ ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ํ•ญ๋ชฉ๊ณผ ํ•จ๊ป˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. connection.readyState๋Š” ์˜์›ํžˆ 0์œผ๋กœ ์œ ์ง€๋˜๋ฉฐ ์—ฐ๊ฒฐ๋œ ์ด๋ฒคํŠธ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ œ ์ƒ๊ฐ์—๋Š” require('mongoose') !== require('mongoose') ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์˜๋ฏธ๊ฐ€ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ฆ‰:

  1. ์‚ฌ์šฉ์ž ์Šคํฌ๋ฆฝํŠธ require('mongoose')
  2. ํ”Œ๋Ÿฌ๊ทธ์ธ require('mongoose')
  3. ํ”Œ๋Ÿฌ๊ทธ์ธ b require('mongoose')

์‚ฌ์šฉ์ž ์Šคํฌ๋ฆฝํŠธ์™€ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์—ฐ๊ฒฐ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ”Œ๋Ÿฌ๊ทธ์ธ b๋Š” ์ ˆ๋Œ€ ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ง์ด ๋ฉ๋‹ˆ๊นŒ?

@r3wt ์ฐธ์œผ๋กœ ๊ทธ ์ดํ›„ ์˜ฌ๋ฐ”๋ฅธ ์ผ ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค . ๋ถˆํŽธ์„ ๋ผ์ณ๋“œ๋ ค ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ์ด ์ค€๋น„๋  ๋•Œ๊นŒ์ง€ ์ฐจ๋‹จํ•˜๋ ค๋ฉด mongoose.connection.on('connected') ๊ฐ€ ์ž‘๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์–ด๋–ค ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ์‹คํ–‰ ํ•ด๋ณด์‹ญ์‹œ์˜ค npm list | grep "mongoose" ๊ฒƒ์„, ๋‹น์‹ ์˜ ์ฃผ์žฅ์„ require('mongoose') !== require('mongoose') ๋‚˜์—๊ฒŒ ๋‹น์‹ ์€ ๋ชฝ๊ตฌ์Šค ๊ณณ์˜ ์—ฌ๋Ÿฌ ๋ฒ„์ „์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋ถˆํ–‰ํžˆ๋„ mongodb ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ๋ฆด๋ฆฌ์Šค๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋‹ค์‹œ ๋ฐ€์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฃ„์†กํ•˜๊ณ  ๊ธฐ๋‹ค๋ ค์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค :+1: ๐ŸŒด

@vkarpov15 ์ด ์ˆ˜์ • ์ž‘์—…์— ๋Œ€ํ•ด ์ •๋ง ๊ฐ์‚ฌํ•˜๋‹ค๋Š” ๋ง์„ ์ „ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” 0 ๋ฌธ์ œ๋กœ ์ง€๊ธˆ ๋ช‡ ๋‹ฌ ๋™์•ˆ ํ”„๋กœ๋•์…˜์—์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@bendytree ์ด ๋ฌธ์ œ๋ฅผ ์žฌํŽธ์ง‘ํ•˜๋Š” ๋ฐ ์žˆ์–ด ๋‹น์‹ ์˜ ์นœ์ ˆํ•œ ๋ง๊ณผ ์ธ๋‚ด์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. mongodb ๋“œ๋ผ์ด๋ฒ„ ํŒ€์€ mongodb 3.6 ๋ฆด๋ฆฌ์Šค์— ๋งž์ถฐ 3.0์„ ๋ฆด๋ฆฌ์Šคํ•˜๋Š” ์ž‘์—…์— ๋ชฐ๋‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ทธ๋“ค์€ ์•„์ง ์ด ์ˆ˜์ •์œผ๋กœ 2.x ๋ฆด๋ฆฌ์Šค๋ฅผ ๋‚ด๋†“์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ping์„ ๋ณด๋‚ด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ฆ๊ฑฐ์šด ํœด์ผ ๋ณด๋‚ด์„ธ์š”!

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰