Node-redis: لا تتم إعادة تعيين retry_strategy بعد مسح الخطأ

تم إنشاؤها على ١٨ فبراير ٢٠١٧  ·  21تعليقات  ·  مصدر: NodeRedis/node-redis

  • الإصدار : node_redis 2.6.5، redis 3.2.7
  • النظام الأساسي : Node.js 7.5.0 على نظام التشغيل Mac OS 10.12.3
  • الوصف :

أنا أستخدم الكود التالي

const redis = require('redis');

const client = redis.createClient({
  url: 'redis://localhost:6379',
  retry_strategy: options => new Error('Fail')
});

setInterval(() => client.incr('some-key', console.log), 5000);

الجري ضد redis محلي ( docker run --rm -p 6379:6379 redis )

بعد أن أرى الناتج الأول ، أقتل redis لمحاكاة قطع الاتصال. عندما رأيت الخطأ يأتي ، أعيد تشغيل redis. الاتصال لا يأتي مرة أخرى. أتوقع أنه بعد مسح الخطأ للمعالجات غير المتصلة بالإنترنت ، سيحاول العميل إعادة الاتصال في الأمر التالي. بدلا من ذلك يبقى في حالة مغلقة. كما أنه يعود AbortError بدلاً من new Error('Fail') .

Feature Request

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

تحديث سريع هنا.
لقد أضفت enable_offline_queue = false إلى خياراتي createClient ، ويبدو أنني فعلت ما أريده ، وهو:
"استمر في محاولة إعادة الاتصال بخادم Redis الخاص بي بناءً على الوظيفة retry_strategy ، ولكن قم برمي الأخطاء فورًا استجابةً لمحاولات استخدام العميل في هذه الأثناء. وبعد ذلك ، إذا تمكنت من إعادة الاتصال ، فابدأ العمل مرة أخرى ".

لمعلوماتك: يعرض الخطأ التالي على مكالمة get : AbortError: SET can't be processed. Stream not writeable.

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

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

ربما هناك الكثير من السيناريوهات الصعبة التي يجب مراعاتها هنا ...

ال 21 كومينتر

من خلال وثائق retry_strategy ، يبدو أن node_redis سيحاول فقط إعادة الاتصال إذا كانت الوظيفة تُرجع رقمًا.

إذا قمت بإرجاع رقم من هذه الدالة ، فستحدث إعادة المحاولة بعد ذلك الوقت بالضبط بالمللي ثانية.

في حالتك ، تقوم بإرجاع رقم لا يفي بمتطلبات محاولة إعادة الاتصال.

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

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

مع نسخة معدلة من المثال الوارد في README.md ، يجب أن تكون قادرًا على تحقيق ما تبحث عنه. ومع ذلك ، بمجرد استنفاد المحاولات القصوى وهي 3 ، لن يحاول العميل تلقائيًا إعادة الاتصال في الأمر التالي. أعتقد أنك ستحتاج إلى الاتصال بـ createClient() يدويًا مرة أخرى.

const client = redis.createClient({
    url: 'redis://localhost:6379',
    retry_strategy: (options) => {
        if (options.times_connected >= 3) {
            // End reconnecting after a specific number of tries and flush all commands with a individual error
            return new Error('Retry attempts exhausted');
        }
        // reconnect after
        return 1000;
    }
});

نعم ، لقد تركت المحاولات لأن ذلك لا يحدث فرقًا هنا.

إذن أنت تقصد في الأساس:

let client = createClient();
function createClient () {
  return redis.createClient({
    url: 'redis://localhost:6379',
    retry_strategy: (options) => {
      client = createClient();
      return new Error('Retry attempts exhausted');
    }
  });
}

مما يعني أنه لا يمكنني تمرير عميل redis في الكود الخاص بي بعد الآن؟

يمكنك إنشاء غلاف خفيف لإدارة مثيل فردي لعميل redis.

// redisClient.js

let redis = require("redis");

let client = null;

const options = {
    url: 'redis://localhost:6379',
    retry_strategy: (options) => {
        client = null;
        return new Error("Redis client connection dropped.");
    }
};

module.exports = {
    getClient: () => {
        if (client == null) {
            client = redis.createClient(options);
        }
        return client;
    }
};

ليستخدم:

// usage

let client = require("redisClient.js");

client.getClient().get("some key");
client.getClient().set("some key", "some value");

أفترض أن هذا مشابه جدًا لاستدعاء createClient() في إستراتيجية إعادة المحاولة ، لكنني لست معجبًا كبيرًا بهذه الطريقة.

إذا كنت ترغب في تقليل الحاجة إلى استدعاء getClient() طوال الوقت ، فيمكنك عمل غلاف كبير يغطي جميع مكالمات redis مثل get() ، set() ، إلخ ، و استدعاء getClient() في كل طريقة من تلك الطرق. ومع ذلك ، فإن طريقة getClient() هذه طريقة شائعة جدًا لإدارة الاتصالات بتكاسل وليس بشغف.

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

أنا لست المؤلف ، لذا لست متأكدًا من الدوافع وراء التنفيذ المحدد لاستراتيجية إعادة المحاولة. في استخداماتي الخاصة لـ node_redis ، وجدت أن الوظيفة الحالية لـ retry_strategy مفيدة ، لكنني أوافق على أنها تفتقر إلى القدرة على إعادة المحاولة تلقائيًا بغض النظر عن السبب. في استخداماتي ، أعيد باستمرار رقمًا من retry_strategy ولا أرجع خطأً أبدًا ، لأنني أريد دائمًا إجراء محاولة الاتصال. ومع ذلك ، أقوم بتسجيل الأخطاء من داخل إعادة المحاولة.

ماذا عن شيء مثل هذا؟ https://github.com/viglucci/node_redis/tree/feature-reconnect-after-flush#retry_strategy -example

var client = redis.createClient({
    retry_strategy: function (options) {
        if (options.error && options.error.code === 'ECONNREFUSED') {
            // End reconnecting on a specific error and flush all commands with a individual error
            return new Error('The server refused the connection');
        }
        if (options.total_retry_time > 1000 * 60 * 60) {
            // End reconnecting after a specific timeout and flush all commands with a individual error
            return new Error('Retry time exhausted');
        }
        // attempt reconnect after retry_delay, and flush any pending commands
        return {
            retry_delay: Math.min(options.attempt * 100, 3000),
            error: new Error('Your custom error.');
        }
    }
});

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

var client = redis.createClient({
  // this strategy handles the pending redis commands when the connection goes down
  flush_strategy (options) {
    if (options.attempt >= 3) {
      // flush all pending commands with this error
      return new Error('Redis unavailable')
    }
    // let the connection come up again on its own
    return null;
  },
  // this strategy handles the reconnect of a failing redis
  retry_strategy (options) {
    if (options.total_retry_time > 1000 * 60 * 60) {
      // The connection is never going to get up again
      // kill the client with the error event
      return new Error('Retry time exhausted');
    }
    // attempt reconnect after this delay
    return Math.min(options.attempt * 100, 3000)
  }
});

لا يعجبني حقًا الاسم flush_strategy ولكن يمكن للمرء أن يأتي بشيء أفضل.

يا للاهتمام. ما تقترحه هنا يبدو أشبه بإعادة تسمية retry_strategy إلى connection_strategy واستخدام retry_strategy كما أشرت إليه بـ flush_strategy .

var client = redis.createClient({
    // this strategy handles reconnection
    connection_strategy (options) {
        if (options.total_retry_time > 1000 * 60 * 60) {
            // The connection is never going to get up again
            // kill the client with the error event
            return new Error('Retry time exhausted');
        }
        // attempt reconnect after this delay
        return Math.min(options.attempt * 100, 3000)
    },
    // this strategy handles the pending redis commands when the connection goes down
    retry_strategy (options) {
        if (options.attempt >= 3) {
            // flush all pending commands with this error
            return new Error('Redis unavailable');
        }
        // let the client attempt the commands once a connection is available
        return null;
    },
});

تم التنفيذ: https://github.com/viglucci/node_redis/tree/feature-connection-strategy#retry_strategy -example

Janpot هل يمكنك توضيح حالة الاستخدام عند الحاجة إلى ذلك؟ حاولت تقليل كمية الخيارات لجعلها أسهل في الاستخدام و retry_strategy هو بالفعل خيار قوي.

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

BridgeAR إنه إلى حد كبير الآن ، إذا انقطع اتصال redis لسبب ما ، فإن كل أوامري معلقة فقط. لنفترض أن لديّ احتياطيًا للعملية التي يقوم بها redis بعد ذلك ، فإن هذا الاحتياطي معلق أيضًا. أفضل أن يقوم redis بإرجاع خطأ بعد عدة محاولات ، والتي يمكنني التقاطها واستخدامها الاحتياطي. هذا لا يعني أنني لا أريد أن يتوقف العميل عن محاولة الاتصال. قد يعود Redis في غضون دقيقة.

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

أو قد لا أرى حالة الاستخدام لذلك بالطبع 😄

Bridgear شكرا. حسنًا ، إذا كانت لديك خارطة طريق "الطريق إلى الإصدار 3" بمهام بسيطة مثل إزالة دعم معلمات التكوين / إزالة تحذيرات الإيقاف ، وما إلى ذلك ، فإن ID مهتمة بإرسال طلبات السحب. ربما لن أكون قادرًا على التعامل مع الأعمال الكبيرة مثل إضافة دعم لأوامر redis الإضافية ، ولكن من المحتمل أن أقوم بأشياء بسيطة لتنظيف المنزل إذا كانت مفتوحة للعلاقات العامة بمجرد توفر فرع ميزة V3.

viglucci دعوت إليه كمتعاون. سأضع خطة في وقت ما قريبًا

+1 لحل هذه المشكلة.

أنا أستخدم Express ، وبينما لا يزال بلدي retry_strategy يُرجع الأعداد الصحيحة لمحاولة الاتصال مرة أخرى في المستقبل ، تستمر الأوامر (وطلبات الويب) في التراكم / النسخ الاحتياطي بدلاً من رمي شيء ما حتى يتمكنوا من الحصول عليه في حياتهم ... ونأمل أن يتم إعادة تأسيس الاتصال _ في النهاية_ قبل أن تقول الإستراتيجية للتخلي أو أي شيء آخر.

هل يمكن تحقيق ذلك؟ Janpot هل وجدت أي شيء متاح حاليًا لحل هذا الموقف؟

ربما يمكن لشيء ما بخيارات enable_offline_queue و / أو retry_unfulfilled_commands تحقيق ذلك؟

شكرا للجميع لعملكم الشاق ومساعدتكم!

تحديث سريع هنا.
لقد أضفت enable_offline_queue = false إلى خياراتي createClient ، ويبدو أنني فعلت ما أريده ، وهو:
"استمر في محاولة إعادة الاتصال بخادم Redis الخاص بي بناءً على الوظيفة retry_strategy ، ولكن قم برمي الأخطاء فورًا استجابةً لمحاولات استخدام العميل في هذه الأثناء. وبعد ذلك ، إذا تمكنت من إعادة الاتصال ، فابدأ العمل مرة أخرى ".

لمعلوماتك: يعرض الخطأ التالي على مكالمة get : AbortError: SET can't be processed. Stream not writeable.

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

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

ربما هناك الكثير من السيناريوهات الصعبة التي يجب مراعاتها هنا ...

newhouse ،

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

شكرًا لك newhouse ، لست متأكدًا من أنني كنت

يجب أن يكون هذا هو السلوك الافتراضي IMO ، أو على الأقل يتم استدعاؤه صراحةً في المستندات حول retry_strategy . اسمحوا لي أن أعرف إذا كنت تعتقد أن هذا الأخير معقول ، وسأفتح العلاقات العامة لإضافة المستندات.

bwhitty ، فإن مستندات العلاقات العامة من أي شخص سيكون موضع ترحيب كبير 👍

أحد مسكتك باستخدام enable_offline_queue = false هو إرسال الأوامر مباشرة بعد استدعاء createClient ، ولكن قبل فتح الاتصال فعليًا ستفشل أيضًا.

أحد مسكتك باستخدام enable_offline_queue = false هو إرسال الأوامر مباشرة بعد استدعاء createClient ، ولكن قبل فتح الاتصال فعليًا ستفشل أيضًا.

jkirkwood يبدو أنك تريد تأخير محاولة إرسال ready (أو حدث مناسب مشابه)؟

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