طلبات لا نهائية إلى /presence/update

حسنًا، قد لا يكون هذا “خطأ” بحد ذاته وقد يكون مصممًا بهذه الطريقة، ولكن لدي بعض الاستفسارات حول كيفية تحديث الحضور على جانب جافاسكريبت. الملف app/assets/javascripts/discourse/app/services/presence.js

ما فهمته حتى الآن هو أن عميل جافاسكريبت:

  • سيقوم بتحديد وتيرة التحديث إلى مرة واحدة في الثانية عندما تكون قائمة التحديثات غير فارغة
  • ثم طلب واحد كل 30 ثانية عندما لا تكون هناك تغييرات

ما لاحظته هو أنه إذا حدث خطأ في الخادم لأي سبب، فسيستمر جافاسكريبت في إرسال طلبات كل ثانية. كما أنه ينشئ أخطاء في وحدة التحكم Uncaught (in promise) السطر 565.
ألا ينبغي أن يتوقف عند نقطة ما بعد N أخطاء لتجنب إرهاق الخادم؟

كيفية إعادة الإنتاج؟

قم بمحاكاة خطأ في طريقة update في presence_controller.rb. (في حالتي، قمت بعرض الحالة 405 لمجرد العرض التوضيحي)

  def update

    # عميل جافاسكريبت مصمم لتحديد وتيرة الطلبات إلى طلب واحد في الثانية
    # عندما لا يتم إجراء أي تغييرات، فإنه يقوم بطلب واحد كل 30 ثانية
    RateLimiter.new(nil, "update-presence-#{current_user.id}", 20, 10.seconds).performed!
    render json: { error: "Not authorized" }, status: 405
    return
    ...

ثم على العميل، انتقل إلى أي شاشة تحتوي على إدارة الحضور. اخترت شاشة الرد على الموضوع وبدأت في الرد.

النتيجة هي أنه سيستمر إلى الأبد وكل ثانية.

إعجاب واحد (1)

وهل هذا ضروري حقًا لإعادة حساب الوجود كل 30 ثانية؟ لأن هناك:

  • حساب عند اتخاذ إجراء enter
  • حساب عند اتخاذ إجراء leave
  • وحساب عندما يتغير وجود المستخدم

هل طلب الميزة هنا هو “التراجع” عند حدوث خطأ، وبهذه الطريقة سنتراجع بالكامل إلى 30 ثانية تقريبًا عند تكرار الأخطاء…

إعجاب واحد (1)

@AhmedLoud هل هذه هي المشكلة التي قمت بإصلاحها عبر https://github.com/discourse/discourse/commit/589add7bb5d01912281c2c38f91325f34567b6bd، أم أنها مشكلة منفصلة؟

إعجاب واحد (1)

@david آسف على سوء الفهم.

لم يكن منشور الموضوع الأول الخاص بي متعلقًا بـ: FIX: use `_presentChannels.size` instead of `_presentChannels.length`… · discourse/discourse@589add7 · GitHub

حتى بدون التحديث المجدول كل 30 ثانية، إذا كان هناك أي خطأ من الواجهة الخلفية، فسيحاول الخوارزمية مرة أخرى كل ثانية لأن قائمة الانتظار للأحداث لن تكون فارغة:

في _scheduleNextUpdate

   } else if (this._queuedEvents.length > 0) {
      this._cancelTimer();
      cancel(this._debounceTimer);
      this._debounceTimer = debounce(
        this,
        this._throttledUpdateServer,
        this._presenceDebounceMs // أعتقد أن هذا هو ثانية واحدة
      );

في الواقع، في طريقة _updateServer → يتم إعادة وضع الأحداث في قائمة الانتظار عند حدوث خطأ:

  } catch (e) {
      // Put the failed events back in the queue for next time
      this._queuedEvents.unshift(...queue);

كان هذا مجرد شيء لاحظته لاحقًا… عندما تسير الأمور على ما يرام (مما يعني عدم وجود أخطاء)، هل من الضروري حقًا الاستمرار في تحديث الخادم كل 30 ثانية؟

} else if (
      !this._nextUpdateTimer &&
      this._presentChannels.size > 0 &&
      !isTesting()
    ) {
      this._nextUpdateTimer = discourseLater(
        this,
        this._throttledUpdateServer,
        PRESENCE_INTERVAL_S * 1000 // هذا هو 30 ثانية
      );
    }
إعجاب واحد (1)

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

إعجاب واحد (1)

حسناً، أعتقد أنني فهمت لماذا يحتاج إلى “تسجيل الدخول” مرة أخرى كل 30 ثانية.

هناك مهمة في الخلفية يتم تشغيلها كل دقيقة PresenceChannelAutoLeave والتي ستجعل الأعضاء المنتهين صلاحيتهم يغادرون القناة.

كما تم التعليق عليه في presence_channel.rb لطريقة present(user:, client_id:):

    # ضع علامة على عميل المستخدم على أنه موجود في هذه القناة. يجب أن يكون client_id فريدًا لكل
    # علامة تبويب في المتصفح. يجب استدعاء هذه الطريقة بشكل متكرر (مرة واحدة على الأقل كل DEFAULT_TIMEOUT)
    # أثناء وجود المستخدم في القناة.
    def present(user:, client_id:)

لا أزال أتساءل عن جزء الخطأ الذي يتم تشغيله كل ثانية.

كنا نتعامل بالفعل مع أخطاء 429 ‘محدود المعدل’ بشكل صحيح. ولكن بالنسبة للأخطاء الأخرى غير المتوقعة، أضفت بعض منطق التراجع الأسي (بحد أقصى 30 ثانية). شكراً على لفت انتباهنا @AhmedLoud

3 إعجابات

تم إغلاق هذا الموضوع تلقائيًا بعد 9 أيام. لم يعد يُسمح بالردود الجديدة.