Mongoose: توقف حدوث عمليات الاسترجاعات

تم إنشاؤها على ١٣ سبتمبر ٢٠١٦  ·  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); }
});

المشكلة

النمس فقط يتوقف عن الاتصال مرة أخرى. لا ينبعث منه أي أخطاء ، والذاكرة / وحدة المعالجة المركزية جيدة على الخادم الخاص بي و 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؟

كانت هذه مشكلة كبيرة بالنسبة لي في الأيام القليلة الماضية. انتهى تشغيل كل تطبيق بحلقة حدث أبطأ وأبطأ ، مما أدى إلى زيادة زمن الوصول في جميع أنحاء النظام بأكمله. أدت إعادة تشغيل تطبيقات Node إلى حل المشكلة في كل مرة ، حيث تعود بعد دقائق أو ساعات من التشغيل.

العودة إلى النمس 4.5.10 حل المشكلة.

  • الاتصال بمجموعة النسخ المتماثلة
  • باستخدام SSL

مشكلة مماثلة هنا مع 4.6.0 ، لست متأكدًا مما إذا كنت أتصل بمجموعة متماثلة أم لا ، ولكن بالتأكيد باستخدام SSL.

FWIW ، 4.6.0 كان يسقط الاتصالات باستمرار. 4.5.10 جيد.

djanowski هل يمكنك تقديم المزيد من المعلومات ، مثل شكل رمز الاتصال الخاص بك وما هو إصدار mongodb لديك؟

@ vkarpov15 كنت

خيارات الاتصال:

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

النمس الواحد أو النمس المتعدد؟

النمس المتعدد. استخدام نشر Compose Mongo.

هل هناك أي شيء آخر يمكنني القيام به للمساعدة في استكشاف الأخطاء وإصلاحها؟ هذا يمنعنا من الانتقال إلى الإصدارات الأحدث ...

من الصعب بالنسبة لي وضع أي فرضية حقيقية دون رؤية التعليمات البرمجية الخاصة بك. إذا كنت تتصل بـ mongoose.connect فسأحقق من قيمة mongoose.connection.readyState عندما تبدأ هذه المشكلة في الحدوث. أيضًا ، سأقوم بتمكين وضع تصحيح أخطاء mongoose ، mongoose.set('debug', true) ، والذي سيطبع رسائل تصحيح الأخطاء إلى وحدة التحكم لكل عملية mongoose. ما إذا كانت هذه الرسائل يتم طباعتها أم لا سيساعد بالتأكيد في التصحيح.

@ vkarpov15 هذا هو الكود الذي أستخدمه للاتصال: https://gist.github.com/sommestad/c0c6a7fa4feaadf84ecbb59cc3432c90
إنها جزء من وحدة خاصة ، ومن هنا جاء الجيست.

_ (سبب وحدة التفاف الاتصال هو إعادة استخدام الاتصال من حين لآخر في وحدات NPM الخاصة الأخرى ، والتي لم تعمل بشكل جيد مع النمس تاريخيًا.) _

لقد تم تمكين تسجيل حالة الاتصال عند حدوث هذه المشكلات ، ولكن يبدو أن الاتصال نفسه لم يتغير (لم تصدر أية أحداث على الأقل). لذلك ، لا يبدو أن العميل مفصول.

لا يتم الاتصال بـ replicaSet في URI (قاعدة البيانات الهدف هي نشر التأليف Compose Deployment ). كما ذكرنا ، يتم استخدام بروتوكول SSL. يتم أيضًا توجيه حركة المرور عبر بوابة AWS NAT. AWS NAT لها مهلة خمول 5 دقائق ، ولكن هذه المشاكل حدثت حتى أثناء حركة المرور العالية.

بعض المشاكل بالنسبة لي هل قمت بحلها؟

@ youth7 كلا لا توجد أفكار. هل تتصل أيضًا بنشر إنشاء؟ يرجى تقديم معلومات إضافية

هل يمكنني فعل أي شيء آخر لمحاولة العثور على سبب ذلك؟ أي نظريات يمكن التحقيق فيها؟

sommestad لا شيء ملموس. هل لديك أي سجلات من تأليف؟

جربت mongoose 4.7.2 لكنني واجهت نفس المشكلة بعد 48 ساعة. في هذه المرحلة ، أتعامل مع 4.4.11 الذي لديه مشكلات خاصة به.

لقد قمت بتثبيت 4.7.2 على الخادم التجريبي الخاص بنا على أمل جمع السجلات ، ولكن تم تشغيله لمدة أسبوعين دون مشكلة. ربما حجم البيانات / الاتصالات / إلخ يثير المشكلة؟

بمجرد أن يبدأ في الحدوث ، فإن الكود الخاص بإعادة إنتاجه يكون بسيطًا للغاية. في الأساس ، يختفي رد الاتصال الخاص بأي استعلام:

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

كما ذكرت ، عندما يحدث هذا ، mongoose.connection.readyState === CONNECTED

عجيب. أعني سجلات mongodb - هل يمكنك تفريغ سجلات خادم mongodb من وقت حدوث هذا الخطأ؟

لقد قمت بمسح سجلات قاعدة البيانات عندما حدث هذا الفشل ولم أتمكن من رؤية أي شيء خارج عن المألوف. لم تكن هناك مشكلات تتعلق بعدد الاتصالات أو قطع الاتصال أو مشكلات الاتصال أو ما شابه ذلك. لقد تواصلت أيضًا مع Compose الذي لم يستطع رؤية أي شيء خارج الترتيب أيضًا.

bendytree هل يمكنك

bendytree أيضًا ، هل يحدث ذلك في جميع أسطر إصدار Node (4.x و 6.x و 7.x)؟

@ vkarpov15 هل يمكننا إخراج 4.7.7 من الباب حتى أتمكن من الاختبار باستخدام أحدث برنامج تشغيل MongoDB؟ 4.7.6 مثبت بإصدار يبدو أنه مهمل.

@ vkarpov15 66d559b19a86c70e30a8f083d03eb22566571b7e شكرًا! سأجربه.

نفس الشيء هنا ، نسخة طبق الأصل من SSL هنا ، بعد بضع دقائق / ساعات ، تتوقف الطلبات عن رد الاتصال () (لقد أضفت المزيد من التسجيل المطول) ولا توجد أخطاء. لقد قمت بالترقية إلى 4.7.7 الليلة الماضية ولكن لا تزال لدي المشكلة.

تحرير: حاولت الرجوع إلى 4.7.0 ولكنه كان الأسوأ (واجهت المشكلة في أقل من 5 دقائق). أحاول 4.5.10.

gierschv العقدة 6.9.x؟

djanowski لا ، لا يزال على 4.6 / 4.7.x LTS.

djanowski لقد جربته فقط على Node 4.4.2

الاحتفاظ بقائمة التكرارات المحتملة لهذه المشكلة:

  • # 4638
  • # 4690
  • # 4901

لمعلوماتك ، يبدو أن 4.5.10 يعمل بشكل جيد هنا ، ولا توجد مشكلات خلال آخر 5 ساعات. كان لدي أيضًا استخدام عالي لوحدة المعالجة المركزية مثل # 4690 على جميع الأجهزة التي يبدو أنها تم إصلاحها أيضًا من خلال الرجوع إلى إصدار أقدم.

لا توجد تطورات جديدة هنا؟ أي شيء يمكننا القيام به للمساعدة في العثور على الخطأ؟

sommestad هل ما زلت تواجه هذه المشكلة مع أحدث النمس؟

لم أجرؤ على إجراء ترقية بعد ، نظرًا لأنه كسر نظامنا بالكامل في المرة الأخيرة (تظهر التغييرات بعد "بعض الوقت" لذلك يصعب التحقق دون تشغيله لفترة طويلة). إذا كان لديك سبب للاعتقاد بأنه تم إصلاحه ، فيمكننا تجربة جزء أكثر عزلة من النظام؟

تحرير: pingvarunjayaraman

من جانبي ، قمنا بالتبديل إلى 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 وتشغيل الطلبات إلى نقطتي نهاية (عادية / بطيئة) والتي يتم استدعاؤها بهذا الترتيب:

  1. نقطة النهاية العادية (التي ترجع النتائج على الفور)
  2. نقطة نهاية بطيئة (والتي ستبدأ استعلامًا بطيئًا)
  3. نقطة نهاية عادية (والتي ستنتظر اتصالاً متاحًا نظرًا لأنه قيد الاستخدام قبل 2)
  4. نقطة نهاية عادية (والتي سيتم تشغيلها بعد دقيقة ، عندما نتج عن 2 و 3 خطأ MongoError / مهلة الاتصال)

استنساخ باستخدام:

// 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 ثوانٍ ، مما يشير إلى أن الاتصال لا يزال نشطًا. لم يتم تشغيل حدث خطأ 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

أي مساعدة سوف أقدر لي كثيرا.

لذلك قمت ببعض عمليات الحفر لإعادة كتابة النص أعلاه للعمل مع node-mongodb-native دون استخدام النمس. النتائج مختلفة جدًا الآن:

إعدادات وطلبات الاتصال هي نفسها:

  1. نقطة النهاية العادية (التي ترجع النتائج على الفور)
  2. نقطة نهاية بطيئة (والتي ستبدأ استعلامًا بطيئًا)
  3. نقطة نهاية عادية (والتي ستنتظر اتصالاً متاحًا نظرًا لأنه قيد الاستخدام قبل 2)
  4. نقطة نهاية طبيعية (والتي ستبدأ بعد دقيقة)

الشفرة:

// 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
  • mongodb 2.2.30
  • النمس 4.11.5

لقد قمت بالتحديث إلى:

  • العقدة 6.8.1
  • mongodb 2.2.31
  • النمس 4.11.7

لا يزال بإمكاني إعادة إنتاج المشكلة محليًا باستخدام البرنامج النصي الأول الذي قمت بنشره. يحدث فقط عندما تنتهي مهلة اتصال Mongo ، لذلك قد ترغب في تغيير الاستعلام الذي يحاكي هذا:

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

(لست متأكدًا مما إذا كان هذا سيؤدي إلى انتهاء المهلة على كل جهاز ، لذا قد يكون من الضروري إعادة إنتاج هذا الاستعلام)

لم نعد نرى هذه المشكلات بعد التحديث إلى mongoose 4.10.4.
يبدو غريباً بعض الشيء ، حيث يبدو أن الآخرين يواجهون مشكلات ، ولكن لديهم العديد من الخدمات قيد التشغيل لمدة أسبوعين دون أي علامات على عودة المشكلة. 🤔

ومع ذلك ، فقد رأينا المشكلات بالطريقة نفسها التي رأينا بها

تشغيل عقدة 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 هل يمكنك تجربة هذا البرنامج النصي المحدث. لقد اختبرت وأعدت باستخدام النمس 4.8.11.

تمكنت من إعادة عرضه مع socketTimeoutMS منخفضة جدًا. ال

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 ثانية بشكل افتراضي ، ولكن نظام التشغيل لديك يحتوي أيضًا على مهلة مأخذ يجب أن تكون على دراية بها ، لذلك من الجيد عمومًا تجنب الاستعلامات التي تستغرق أكثر من 15 ثانية. ومع ذلك ، يمكنك تكوين مهلة مأخذ mongodb باستخدام الخيار socketTimeoutMS :

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 (افتراضيًا يبلغ 30000 مللي ثانية) مع socketTimeoutMS (افتراضيًا يبلغ 360000 مللي ثانية).

يُنصح بضبط socketTimeoutMS على ضعفين إلى ثلاثة أضعاف طول أبطأ عملية تمر عبر برنامج التشغيل ، ويعني تعيين socketTimeoutMS على 0 في الواقع تطبيق قيمة مهلة مأخذ التوصيل الافتراضية لنظام التشغيل (مزيد من المعلومات على http://mongodb.github.io/ node-mongodb-native / 2.2 / reference / faq /).

لذلك يبقى هذا السؤال: لماذا تتوقف عمليات الاسترجاعات هذه عند الوصول إلى هذا الحد (مهلة نظام التشغيل الثابتة أو الافتراضية)؟

@ vkarpov15 مع [email protected] ، أرى الآن حدث timeout ، شكرًا على ذلك. ومع ذلك ، لا تزال ترى مشكلة رد الاتصال هذه (باستخدام البرنامج النصي الأصلي bendytree ، لإجراء اختبار أسرع ، يمكنك تعيين LONG_QUERY_DURATION_IN_MS على 2000 و socketTimeoutMS إلى 1000)

لقد أجريت المزيد من الاختبارات واكتشفت أن هذا يمكن إعادة إنتاجه بدون النمس أيضًا. عند قراءة 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...

لذلك يبدو أن عمليات الاسترجاعات تعمل مع ضبط إعادة الاتصال التلقائي على "صحيح" 👍

بعد قراءة المزيد من هذه المقالة: http://mongodb.github.io/node-mongodb-native/2.0/tutorials/connection_failures/ ، أدركت أن سبب عدم حدوث عمليات الاسترجاعات بعد انتهاء المهلة هو أن العملية هي مخزنة أثناء انتظار الخادم لإعادة الاتصال.

لذلك حاولت إعادة تعيين autoReconnect إلى false + عيّن 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

وهو ما يفسر سبب عدم تشغيل رد النداء في الإصدار الأول من البرنامج النصي

@ vkarpov15 هذا يترك لنا الآن سؤالين:

  • لماذا لا يتم إصدار أحداث اتصال (أتوقع أن أرى حدثًا غير متصل)
  • يبدو أن حدث المهلة يستمر في الانبعاث

إليك النص المحدث (بناءً على نص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 ضروري ، لكنه ليس كافياً للتعامل مع هذه الحالة.

سبب عدم إرسال "غير متصل" هو أن "المهلة" تعني انتهاء مهلة مأخذ واحد ، وليس المجموعة بأكملها. سيحتاج النمس إلى معرفة عدد مآخذ التوصيل الموجودة في المسبح التي لا تزال على قيد الحياة عند وقوع حدث انتهاء المهلة ، وسأحتاج إلى مزيد من البحث لمعرفة كيفية القيام بذلك.

سنحقق أكثر في سبب استمرار إعادة إصدار حدث المهلة. نشكرك على سعة صدرك: +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 الأخرى والأشياء التي تستمع للأحداث ، فهي مكان حدوث المشكلة. connect.ready الدولة تبقى 0 إلى الأبد ولا يتم إطلاق الحدث المتصل.

يبدو أن require('mongoose') !== require('mongoose') في رأيي. آمل أن يكون هذا منطقيًا.

بمعنى آخر:

  1. برنامج نصي للمستخدم require('mongoose')
  2. المساعد a require('mongoose')
  3. المكون الإضافي b require('mongoose')

يتلقى البرنامج النصي للمستخدم والمكوِّن الإضافي معلومات حول الاتصال. لكن البرنامج المساعد ب لا يفعل ذلك أبدًا. هل له معنى؟

@ r3wt في الواقع ، إنه أمر الاختبارات التي تعمل على إيقاف / بدء تشغيل خادم mongodb وتؤكد أن النمس يفعل الشيء الصحيح لمنع حدوث ذلك في المستقبل. نحن آسفون لهذه المشكلة.

بالنسبة للحظر حتى يصبح الاتصال جاهزًا ، يجب أن يعمل mongoose.connection.on('connected') . ما المكونات الإضافية الأخرى التي تستخدمها؟ حاول تشغيل npm list | grep "mongoose" ، تأكيدك على أن require('mongoose') !== require('mongoose') يجعلني أعتقد أن لديك نسخًا متعددة من النمس في مكان ما.

لسوء الحظ ، سيتعين علينا دفع هذا مرة أخرى مرة أخرى لأن سائق mongodb تم إعاقته عن الإفراج. آسف لذلك وشكرا على صبرك: +1: 🌴

@ vkarpov15 أردت فقط أن أقول شكراً جزيلاً لعملك على هذا الإصلاح. لقد استخدمناه في الإنتاج لبضعة أشهر حتى الآن بدون مشاكل.

bendytree شكرًا على كلماتك الرقيقة وصبرك في إعادة معالجة هذه المشكلة. تم إغراق فريق سائق mongodb بالعمل على إصدار 3.0 في الوقت المناسب لإصدار mongodb 3.6 ، لذلك لم يتمكنوا من إصدار إصدار 2.x مع هذا الإصلاح حتى الآن ، سأقوم باختبار اتصالهم مرة أخرى. اجازة سعيدة!

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات