Mongoose: لم يتم إجراء أي محاولات لإعادة المحاولة بعد "فشل الاتصال عند الاتصال الأول"

تم إنشاؤها على ١٧ أبريل ٢٠١٧  ·  40تعليقات  ·  مصدر: Automattic/mongoose

بشكل افتراضي ، يلقي النمس خطأ إذا فشل الاتصال الأول ، مما يؤدي إلى تعطل العقدة.

لذا لإعادة إنتاج هذا الخطأ ، ستحتاج إلى الكود التالي في تطبيقك ، للقبض على الخطأ ومنع التعطل:

db.on('error', console.error.bind(console, 'connection error:'));

الآن يمكننا إعادة إنتاج هذا الخطأ على النحو التالي:

  1. قم بإيقاف تشغيل MongoDB
  2. ابدأ تشغيل تطبيق العقدة الذي يستخدم النمس
  3. سيقوم تطبيقك بتسجيل: [MongoError: failed to connect to server [localhost:27017] on first connect [MongoError: connect ECONNREFUSED 127.0.0.1:27017]]
  4. ابدأ تشغيل برنامج MongoDB مرة أخرى
  5. لاحظ أن النمس لا يتصل الآن بـ MongoDB العامل. الطريقة الوحيدة لإعادة الاتصال هي إعادة تشغيل التطبيق ، أو استخدام حل يدوي .

السلوك المتوقع: نظرًا لأن الإعداد الافتراضي autoreconnect true ، أتوقع أن يقوم النمس بإنشاء اتصال بعد وقت قصير من إمكانية الوصول إلى MongoDB مرة أخرى.

ملاحظة: إذا نجح الاتصال الأول ، ولكن فُقد الاتصال بـ MongoDB أثناء وقت التشغيل ، فعندئذٍ يعمل الاتصال التلقائي بشكل جيد ، كما هو متوقع. تكمن المشكلة في عدم الاتساق إذا لم يكن MongoDB متاحًا عند بدء تشغيل التطبيق.

(إذا كان هذا هو السلوك المطلوب ، ويوصى المطورون بمعالجة هذا الموقف من خلال عدم اكتشاف الخطأ ، والسماح بتعطل العقدة ، عندئذٍ يمكنني قبول ذلك ، لكن الأمر يستحق توضيحه.)

العقدة v4.4.1 ، [email protected] ، [email protected] ، [email protected]

docs

التعليق الأكثر فائدة

بالنسبة لأي شخص يريد إعادة الاتصال التلقائي عند فشل الاتصال لأول مرة ، فهذه هي الطريقة التي أتعامل بها مع الأمر:

function createConnection (dbURL, options) {
    var db = mongoose.createConnection(dbURL, options);

    db.on('error', function (err) {
        // If first connect fails because mongod is down, try again later.
        // This is only needed for first connect, not for runtime reconnects.
        // See: https://github.com/Automattic/mongoose/issues/5169
        if (err.message && err.message.match(/failed to connect to server .* on first connect/)) {
            console.log(new Date(), String(err));

            // Wait for a bit, then try to connect again
            setTimeout(function () {
                console.log("Retrying first connect...");
                db.openUri(dbURL).catch(() => {});
                // Why the empty catch?
                // Well, errors thrown by db.open() will also be passed to .on('error'),
                // so we can handle them there, no need to log anything in the catch here.
                // But we still need this empty catch to avoid unhandled rejections.
            }, 20 * 1000);
        } else {
            // Some other error occurred.  Log it.
            console.error(new Date(), String(err));
        }
    });

    db.once('open', function () {
        console.log("Connection to db established.");
    });

    return db;
}

// Use it like
var db = createConnection('mongodb://...', options);
var User = db.model('User', userSchema);

بالنسبة إلى النمس <4.11 ، استخدم db.open() بدلاً من db.openUri()
لا تعمل هذه التقنية مع النمس 4.11.7.
بالنسبة للنمس 4.13.4 يعمل مرة أخرى!


تحرير 2019/09/02: يوجد أيضًا حل أقصر باستخدام promiseRetry هنا .

ال 40 كومينتر

يمكن تأكيد.
العقدة 6 ، 7 ، النمس (في leas 6 أشهر) ، mongo 3.2 - 3.4
يأتي مع هذا واحد # 4890

أظن أن هذه مشكلة mongodb-core . يجب أن تحاول إعادة الاتصال حتى لو فشلت المحاولة الأولى على ما أعتقد ، لأنني لست متأكدًا من سبب اختلاف ذلك عن المحاولات اللاحقة.

هل يمكنك أيضًا الإبلاغ عن هذه المشكلة هناك؟

فيما يلي نص برمجي كامل:

const mongoose = require('mongoose');
const co = require('co');
mongoose.Promise = global.Promise;
const GITHUB_ISSUE = `gh-5169`;


exec()
  .catch(error => {
    console.error(`Error: ${ error }\n${ error.stack }`);
  });


function exec() {
  return co(function*() {
    const db = mongoose.createConnection(`mongodb://localhost:27017/${ GITHUB_ISSUE }`);
    db.on('error', (error) => {
      console.error(`in an error ${ error }\n${ error.stack }`);
    })
  });
}

شكرا على التوبيخ. لقد بحثت في mongodb-core. هو السلوك المقصود للسائق :

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

الأمر متروك للتطبيق ليقرر ما يجب فعله. هذا حسب التصميم لضمان فشل السائق بسرعة وعدم الجلوس هناك مما يجعلك تعتقد أنه يعمل بالفعل.

لذلك أظن أننا لن نحصل على أي سلوك مختلف من السائق.

أعتقد في الواقع أن هذا السلوك معقول بالنسبة للسائقين ذوي المستوى المنخفض. سيساعد المطورين الذين يحاولون بطريق الخطأ الاتصال بالمضيف الخطأ أو المنفذ الخطأ.

ولكن إذا أردنا أن نفعل شيئًا أكثر ملاءمة للمطورين في النمس ، فيمكننا التفكير في:

  • عند تمكين خيارات إعادة الاتصال التلقائي ، استمر في محاولة إعادة الاتصال حتى يمكن الاتصال بخادم Mongo (من خلال البناء في شيء مثل الحل البديل المرتبط أعلاه).
  • سجل عندما يقوم النمس بذلك ، لذلك في حالة وجود اتصال لا يتم إنشاءه أبدًا ، سيعرف المطور على الأقل مكان المشكلة.
    (يمكن تأجيل السجل ، على سبيل المثال 30 ثانية. في الواقع بدلاً من التسجيل المباشر ، أعتقد أننا يجب أن نصدر حدثًا استشاريًا error ، ولكن مع ذلك نحاول إعادة الاتصال تلقائيًا.)

إذا كنت أتذكر بشكل صحيح ، عندما استخدمت الحل البديل واتصلت أخيرًا بعد عدة محاولات فاشلة ، تم تنفيذ الاستعلامات الموجودة في قائمة الانتظار بالفعل بواسطة التطبيق كما هو مطلوب. (لكن هذا يستحق الاختبار مرة أخرى.)

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

لا ، يعد الفشل السريع في الاتصال الأولي سلوكًا ثابتًا إلى حد كبير عبر برامج تشغيل MongoDB ولا توجد فائدة كبيرة لدعمه.

قد تكون هذه المشاركة الأخيرة من موصل Strongloop Loopback mongodb ذات صلة. علمهم lazyConnect يؤجل الاتصال الأول حتى يتم الوصول إلى نقطة النهاية. إذا فشل الاتصال الأول في هذه الحالة ، فسوف يتم تفعيل إعدادات فقدان الاتصال الافتراضية (ستتم إعادة المحاولة).

اهتماماتي هي تنسيق الحاوية ، حيث يمكن غالبًا تعيين "طلب بدء تشغيل الحاوية" وتوقعه ولكن "ترتيب توفر الخدمة" لا يمكن ذلك. قد تؤكد أداة التزامن أن حاوية mongo "تعمل" على الرغم من عدم توفر خدمة mongo حتى الآن.

لذلك ، إذا كانت حاوية mongo الخاصة بي تستغرق 1 ثانية لتبدأ ولكن 5 ثوانٍ لتصبح الخدمة متاحة ، وتستغرق حاوية التطبيق 1 ثانية للبدء و 1 ثانية حتى تكون الخدمة متاحة ، فستتجاوز خدمة التطبيق خدمة mongo ، مما يتسبب في فشل الاتصال الأول كما تم وصفه في الأصل .

توضح وثائق Docker Compose ما يلي:

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

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

لمعالجة هذا الأمر ، يجب أن يحاول التطبيق الخاص بك إعادة إنشاء اتصال بقاعدة البيانات بعد الفشل. إذا أعاد التطبيق محاولة الاتصال ، فمن المفترض أن يتمكن في النهاية من الاتصال بقاعدة البيانات.

أفضل حل هو إجراء هذا الفحص في رمز التطبيق الخاص بك ، عند بدء التشغيل وكلما فُقد الاتصال لأي سبب من الأسباب .

إذن ، هناك فجوة محددة هنا في سياق تنسيق الحاوية ، ولكن يبدو أن كلا الموقفين صالح:

  1. يمكن أن يدعم Mongoose خيارًا لإعادة المحاولة عند الاتصال الأول (ربما يكون افتراضيًا على خطأ مع بعض الوثائق التحذيرية) ، أو
  2. يمكن أن يضع Mongoose على عاتق المطور مسؤولية كتابة التعليمات البرمجية لإعادة المحاولة إذا فشل الاتصال لأول مرة.

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

الموقف 2 ، إذن.

بالنسبة لأي شخص يريد إعادة الاتصال التلقائي عند فشل الاتصال لأول مرة ، فهذه هي الطريقة التي أتعامل بها مع الأمر:

function createConnection (dbURL, options) {
    var db = mongoose.createConnection(dbURL, options);

    db.on('error', function (err) {
        // If first connect fails because mongod is down, try again later.
        // This is only needed for first connect, not for runtime reconnects.
        // See: https://github.com/Automattic/mongoose/issues/5169
        if (err.message && err.message.match(/failed to connect to server .* on first connect/)) {
            console.log(new Date(), String(err));

            // Wait for a bit, then try to connect again
            setTimeout(function () {
                console.log("Retrying first connect...");
                db.openUri(dbURL).catch(() => {});
                // Why the empty catch?
                // Well, errors thrown by db.open() will also be passed to .on('error'),
                // so we can handle them there, no need to log anything in the catch here.
                // But we still need this empty catch to avoid unhandled rejections.
            }, 20 * 1000);
        } else {
            // Some other error occurred.  Log it.
            console.error(new Date(), String(err));
        }
    });

    db.once('open', function () {
        console.log("Connection to db established.");
    });

    return db;
}

// Use it like
var db = createConnection('mongodb://...', options);
var User = db.model('User', userSchema);

بالنسبة إلى النمس <4.11 ، استخدم db.open() بدلاً من db.openUri()
لا تعمل هذه التقنية مع النمس 4.11.7.
بالنسبة للنمس 4.13.4 يعمل مرة أخرى!


تحرير 2019/09/02: يوجد أيضًا حل أقصر باستخدام promiseRetry هنا .

مرحبًا @ vkarpov15 عند حدوث ذلك ، قم أيضًا بتسجيل رفض غير معالج من مكتبة mongodb-core.

MongoError: failed to connect to server [localhost:27017] on first connect [MongoError: connect ECONNREFUSED 127.0.0.1:27017]
    at Pool.<anonymous> (/Users/development/okkralabs/sem-server/services/sem-access/node_modules/mongodb-core/lib/topologies/server.js:336:35)
    at emitOne (events.js:116:13)
    at Pool.emit (events.js:211:7)
    at Connection.<anonymous> (/Users/development/okkralabs/sem-server/services/sem-access/node_modules/mongodb-core/lib/connection/pool.js:280:12)
    at Object.onceWrapper (events.js:317:30)
    at emitTwo (events.js:126:13)
    at Connection.emit (events.js:214:7)
    at Socket.<anonymous> (/Users/development/okkralabs/sem-server/services/sem-access/node_modules/mongodb-core/lib/connection/connection.js:187:49)
    at Object.onceWrapper (events.js:315:30)
    at emitOne (events.js:116:13)
    at Socket.emit (events.js:211:7)
    at emitErrorNT (internal/streams/destroy.js:64:8)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)

هذا من السهل إعادة إنتاجه ، حاول الاتصال بخادم MongoDb غير متاح.

(node:2545) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: failed to connect to server [localhost:27017] on first connect [MongoError: connect ECONNREFUSED 127.0.0.1:27017]
(node:2545) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

طريقة ما للتعامل معها؟

jorgearanda ما هو إصدار النمس الذي تستخدمه وهل يمكنك تقديم بعض نماذج التعليمات البرمجية؟

@ vkarpov15 أعتقد أن هذه رسالة لـ jorgecuesta ؟

Woops ، خطأي. github السخيفة الإكمال التلقائي ، نعم ، كان ذلك لـ jorgecuesta

أرى نفس الشيء تمامًا مثل jorgecuesta ، كنت

2018-01-07 13:05:23-05:00: [INFO] database - reusing existing connectioun for mongodb://localhost/eiss
2018-01-07 13:05:23-05:00: [INFO] database - initializing database connection to: mongodb://localhost/eiss
2018-01-07 13:05:23-05:00: [INFO] database - reusing existing connectioun for mongodb://localhost/eiss
2018-01-07 13:05:23-05:00: [ERROR] database - Mongoose connection error: MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017]
Unhandled rejection MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017]
    at Pool.<anonymous> (/Users/bill/eiss4/js/node_modules/mongoose/node_modules/mongodb-core/lib/topologies/server.js:503:11)
    at emitOne (events.js:116:13)
    at Pool.emit (events.js:211:7)
    at Connection.<anonymous> (/Users/bill/eiss4/js/node_modules/mongoose/node_modules/mongodb-core/lib/connection/pool.js:326:12)
    at Object.onceWrapper (events.js:317:30)
    at emitTwo (events.js:126:13)
    at Connection.emit (events.js:214:7)
    at Socket.<anonymous> (/Users/bill/eiss4/js/node_modules/mongoose/node_modules/mongodb-core/lib/connection/connection.js:245:50)
    at Object.onceWrapper (events.js:315:30)
    at emitOne (events.js:116:13)
    at Socket.emit (events.js:211:7)
    at emitErrorNT (internal/streams/destroy.js:64:8)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)

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

const allConnections = {};

module.exports = function(dbName) {
  const url = 'http://localhost/' + dbName;
  let conn;
  log.info('initializing database connection to: ' + url);

  conn = allConnections[url];
  if (!conn) {
    log.info('creating new connection for ' + url);
    conn = mongoose.createConnection(url, {
      useMongoClient: true,
      autoReconnect: true,
      autoIndex: false,
      reconnectTries: Number.MAX_SAFE_INTEGER
    });    
    // Log database connection events
    conn.on('connected', () => log.info('Mongoose connection open to ' + url));
    conn.on('error', (err) =>  log.error('Mongoose connection error: ' + err));
    conn.on('disconnected', () => log.error('Mongoose connection disconnected'));  
    allConnections[url] = conn;
  }
  else {
    log.info('reusing existing connection for ' + url);
  }
  return conn;
}

raythree في الحالة أعلاه يجب أن تكون بخير لأن لديك .on('error') . إذا كنت ترغب في إعادة محاولة الاتصال الأولي إذا فشل ، فإنني أوصيك باستخدام غير المتزامن / انتظار ذلك بالرغم من ذلك

let conn;
for (let i = 0; i < numRetries; ++i) {
  try {
    conn = await mongoose.createConnection(uri);
    break;
  } catch (error) {}
}

@ vkarpov15 آسف على التأخير في الرد ، نحن نستخدم 4.11.14 و 4.13.4

jorgecuesta تفعل mongoose.connect(uri).catch(err => {})

@ vkarpov15 connect () إرجاع مثيل الاتصال أليس كذلك؟

const connection = mongoose.connect(uri || undefined, {useMongoClient: true});
connection.once('error', (e) => {
  console.error(e, 'mongoose connection error.');
});
connection.once('connected', () => {
  console.log('mongoose connected');
});

في الإصدار 5.0.0 ، قمنا بتغييره بحيث يقوم mongoose.connect() بإرجاع الوعد باستمرار. في 4.x ، تُرجع نسخة اتصال ولكن باستخدام .then() و .catch() حتى تتمكن من استخدامها مع await

مرحبًاjoeytwiddle.

أواجه نفس المشكلة عند النشر في Heroku.
MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017]

على تعليقك في 12 تموز (يوليو) 2017 ، قدمت حلًا / حلًا. أنا جديد في النمس / العقدة. هل يمكن أن تخبرني ما هو الملف الذي يجب أن تدخل فيه وظيفة createConnection؟

أنا أقوم بتشغيل النمس: ^ 5.0.10 ، العقدة: v9.4.0
هتافات

juancarlucci يمكنك وضعها في أي ملف تريده. فقط أطلق عليه اسم النمس واستخدمه لإنشاء نماذجك.

لقد قمت بتحديث التعليق السابق لإظهار مثال على الاستخدام.

joeytwiddle شكرا على مثال الاستخدام! هتافات.

عندما أحاول الاتصال بـ mongo ، ألقى خطأ:

connection error: { MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connection 0 to localhost:27017 timed out]
    at Pool.<anonymous> (/home/wasd_xyz/Desktop/test/node_modules/mongodb-core/lib/topologies/server.js:505:11)
    at emitOne (events.js:116:13)
    at Pool.emit (events.js:211:7)
    at Connection.<anonymous> (/home/wasd_xyz/Desktop/test/node_modules/mongodb-core/lib/connection/pool.js:329:12)
    at Object.onceWrapper (events.js:317:30)
    at emitTwo (events.js:126:13)
    at Connection.emit (events.js:214:7)
    at Socket.<anonymous> (/home/wasd_xyz/Desktop/test/node_modules/mongodb-core/lib/connection/connection.js:256:10)
    at Object.onceWrapper (events.js:313:30)
    at emitNone (events.js:106:13)
    at Socket.emit (events.js:208:7)
    at Socket._onTimeout (net.js:420:8)
    at ontimeout (timers.js:482:11)
    at tryOnTimeout (timers.js:317:5)
    at Timer.listOnTimeout (timers.js:277:5)
  name: 'MongoNetworkError',
  message: 'failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connection 0 to localhost:27017 timed out]' }
(node:5453) UnhandledPromiseRejectionWarning: MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connection 0 to localhost:27017 timed out]
    at Pool.<anonymous> (/home/wasd_xyz/Desktop/test/node_modules/mongodb-core/lib/topologies/server.js:505:11)
    at emitOne (events.js:116:13)
    at Pool.emit (events.js:211:7)
    at Connection.<anonymous> (/home/wasd_xyz/Desktop/test/node_modules/mongodb-core/lib/connection/pool.js:329:12)
    at Object.onceWrapper (events.js:317:30)
    at emitTwo (events.js:126:13)
    at Connection.emit (events.js:214:7)
    at Socket.<anonymous> (/home/wasd_xyz/Desktop/test/node_modules/mongodb-core/lib/connection/connection.js:256:10)
    at Object.onceWrapper (events.js:313:30)
    at emitNone (events.js:106:13)
    at Socket.emit (events.js:208:7)
    at Socket._onTimeout (net.js:420:8)
    at ontimeout (timers.js:482:11)
    at tryOnTimeout (timers.js:317:5)
    at Timer.listOnTimeout (timers.js:277:5)
(node:5453) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:5453) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.


sudo service mongodb status

● mongodb.service - MongoDB Database
   Loaded: loaded (/etc/systemd/system/mongodb.service; enabled; vendor preset: 
   Active: active (running) since Sat 2018-06-23 17:13:28 IST; 13min ago
     Docs: https://docs.mongodb.org/manual
 Main PID: 4224 (mongod)
    Tasks: 24 (limit: 4915)
   CGroup: /system.slice/mongodb.service
           └─4224 /usr/bin/mongod --quiet --config /etc/mongod.conf

Jun 23 17:13:28 Inspiron5370 systemd[1]: Started MongoDB Database.


pranshuchittora هل يمكنك إظهار ملف التكوين

حاول الاتصال بـ IP بدلاً من المضيف المحلي الذي سيعمل على حل مشكلتك.

 let local = "mongodb://127.0.0.1:27017/XXX";
      mongoose.connect(
        local,
        { useNewUrlParser: true }
      );

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

[email protected]
@ أنواع / [email protected]
@ أنواع / [email protected]

async function waitForMongoDBStart(uri: string, timeoutMs: number) {

    return new Promise( async (resolve, reject) => {

        let endTime = Date.now() + timeoutMs;


        while (true) {

            let connectionError: Error;

            function errorHandler(err: Error) {
                connectionError = err;
            }
            mongoose.connection.once("error", errorHandler);

            await mongoose.connect(uri, {
                connectTimeoutMS: 5000, // This timeout applies only after connected & connection lost
                useNewUrlParser: true,
                useFindAndModify: false
            });

            // Time for error event propagation
            await wait(0);

            if ( ! connectionError) {
                mongoose.connection.removeListener("error", errorHandler);
                return resolve(); // All OK, connected
            }

            if (connectionError.name !== "MongoNetworkError") {
                return reject(`Unable to connect mongoDB. Details: ${connectionError}`);
            }

            if (Date.now() > endTime) {
                return reject(`Unable to connect mongoBD in ${timeoutMs} ms. Details: ${connectionError}`);
            }

        }

    });
}

@ vkarpov15 هذا سلوك غير واضح للغاية. من https://mongoosejs.com/docs/connections.html :

connectTimeoutMS - How long the MongoDB driver will wait 
before failing its initial connection attempt. 
Once Mongoose has successfully connected, connectTimeoutMS is no longer relevant.

تشير الوثائق إلى أنه يجب أن يعمل مع الاتصال الأولي ، لكنه لا يعمل. مع وجود خطأ failed to connect to server فإنه يفشل على الفور.

إذا كان سلوكًا متسقًا عبر برامج تشغيل MongoDB ، فسيكون من الجيد أن يكون لديك بعض الخيارات مثل reconnectOnInitialFail والذي سيكون false افتراضيًا

السلوك الحالي هو عكس هذا الذي وصفه vkarpov15 -
لا يهم connectImeoutMS إلا بعد الاتصال الأول (عند الاتصال الأول به
من المتوقع أن يبدأ DB وقبول الاتصال ، وإلا بشكل فوري
تم طرح الخطأ)

sob.، 22 gru 2018 o 13:03 Dmitry Kirilyuk [email protected]
napisał (أ):

إذا كان سلوكًا متسقًا عبر برامج تشغيل MongoDB ، فسيكون من الجيد ذلك
لديك بعض الخيارات مثل إعادة الاتصال ، والتي ستكون خطأ من قبل
إفتراضي

-
أنت تتلقى هذا لأنك علقت.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/Automattic/mongoose/issues/5169#issuecomment-449565468 ،
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/ABY-TjgeI2UqVca050y5YY3zi6w7nMkfks5u7h-vgaJpZM4M-1ur
.

-
فويتشخ فيديريك

الجوال: +48 516661428

إذا كنت أتذكر بشكل صحيح ، فإن connectTimeoutMS مهم في الاتصال الأولي وفقًا لظروف الشبكة ونظام التشغيل. ما هي أهمية connectTimeoutMS بعد الاتصال الأولي؟

في حالتي ، تم إلقاء خطأ فوري عندما لم أتمكن من الاتصال في المحاولة الأولى لمثيل المضيف المحلي على نظامي التشغيل Windows 10 و Alpine Linux (الإصدار غير معروف). لم يبدأ مثيل Mongod بعد.
أمثلة أخرى غير المضيف المحلي؟ أي واحد؟

fiderJokero لقد بحثت أكثر ، وأنا على حق ، connectTimeoutMS مهم فقط حتى تقوم بإجراء اتصال أولي ، socketTimeoutMS يتولى الأمر بعد ذلك. إليك الكود ذي الصلة في برنامج تشغيل MongoDB:

connectTimeoutMS مفيدًا دائمًا لأنك ستحصل عادةً على خطأ DNS أو خطأ في رفض الاتصال. ولكن إذا فتحت ، على سبيل المثال ، خادم TCP الذي يستمع إلى منفذ ولكنه لا يفعل أي شيء في الواقع:

const net = require('net');

const server = net.createServer();

server.listen(27055);

ستلاحظ أن connectTimeoutMS يبدأ في:

const assert = require('assert');
const mongoose = require('mongoose');
mongoose.set('debug', true);

const { Schema } = mongoose;

run().then(() => console.log('done')).catch(error => console.error(error.stack));

async function run() {
  await mongoose.connect('mongodb://localhost:27055', {
    useNewUrlParser: true,
    connectTimeoutMS: 1000,
    socketTimeoutMS: 25000
  });
} 
$ time node gh-5169.js 
MongoNetworkError: connection 0 to localhost:27055 timed out
    at Socket.<anonymous> (/mongoose/node_modules/mongodb-core/lib/connection/connection.js:259:7)
    at Object.onceWrapper (events.js:313:30)
    at emitNone (events.js:106:13)
    at Socket.emit (events.js:208:7)
    at Socket._onTimeout (net.js:407:8)
    at ontimeout (timers.js:475:11)
    at tryOnTimeout (timers.js:310:5)
    at Timer.listOnTimeout (timers.js:270:5)

real    0m2.293s
user    0m0.271s
sys 0m0.043s
$ 

في بعض الأحيان بسبب قيود الشبكة ، يتم حظر عنوان url لـ MongoDB ، حاول تغيير مصدر الشبكة / الإنترنت.

https://stackoverflow.com/questions/47958683/cannot-connect-to-mongodb-atlas-through-mongo-shell؟answertab=active#tab -top

عند إجراء اتصال أولي ، (على الأقل) يمكن أن تحدث ثلاثة أشياء:

  1. هناك mongodb والاتصال ينجح ، yay!

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

  3. الخادم لا يستجيب على الإطلاق ، على سبيل المثال ، جدار الحماية الذي أسقط الحزم بشكل سلبي أو لا يوجد خادم على عنوان IP هذا. (في هذه الحالة ، يتم تشغيل connectTimeoutMS الخاص بـ vkarpov في النهاية.)

لذلك لا يتم استخدام المهلة دائمًا. يتم استخدامه فقط في حالة عدم وجود نجاح أو فشل واضح في الوقت المحدد.

هذا شائع في الشبكات وأيضًا عند التحدث إلى شخص غير متعاون. يمكن أن يحصل طلبك على نوعين من الرفض: "لا!" و .....

شكرا على الشرح القوي joeytwiddle : +1:

كيف يجب التعامل مع هذا السلوك مع اتصالات مجموعة النسخ المتماثلة باستخدام mongodb+srv ؟ عندما تكون مجموعة النسخ المتماثلة الخاصة بي في سيناريو إعادة التشغيل المتداول (تحديث قاعدة البيانات) ، أبدأ في تلقي أخطاء مثل connect ECONNREFUSED 34.238.xxx.xxx:27017 .

esetnik هل تستخدم useUnifiedTopology: true و Mongoose 5.7.5؟ حددنا المشكلة رقم 8209 التي قد تكون ذات صلة.

@ vkarpov15 نعم أنا! شكرا على الاكرامية. سأجري بعض الاختبارات بعد تعطيل الهيكل الموحد وإبلاغ النتائج التي توصلت إليها.

أهلا. لدي نفس المشكلة بالضبط في مشروعي. هل وجدت أي حل لذلك ؟!

fdmxfarhan يرجى فتح إصدار منفصل واتباع نموذج المشكلة.

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