MQTT0 queue overflow!

  • Heute habe ich versucht,

    eine schnelle Warteschlange für den Shelly.call() zu erstellen. Dabei bin ich zufällig auf den MQTT Overflow-Bug gestoßen.

    Mein Skript hat sich auch als Shelly-Benchmark erwiesen, abhängig von den Einstellungen können Out-of-Memory-Fehler, MQTT0 Queue-Overflow-Fehler oder sogar ein Shelly-Absturz verursacht werden.

    In der Konfiguration 20,4,50 treten viele MQTT0 Queue-Overflow-Fehlermeldungen auf, obwohl ich im Skript keine einzige MQTT-Funktion verwende. Wahrscheinlich überlastet diese Konfiguration den Prozessor und beeinträchtigt so die interne MQTT-Warteschlange, was zu den MQTT0 Queue-Overflow-Fehlermeldungen sowie zu einigen interne verlorene Shelly Status MQTT-Nachrichten führt.

    - In der Konfiguration 1000,4,50 crashed das Skript den Shelly, vermutlich aufgrund einer gleichzeitigen Überlastung von Memory und CPU.

    - In der Konfiguration 20,5,100 stoppt das Skript gelegentlich, ohne eine Fehlermeldung zu generieren, wahrscheinlich sind 5 aktive Calls einfach zu viel.

    - In der Konfiguration 1000,4,1000 wird das Skript gestoppt und es wird ne versteckte Out-of-Memory-Fehlermeldung ausgelöst.

    - In der Konfiguration 20,4,500 läuft das Skript problemlos durch.

    Das Script:

    Einmal editiert, zuletzt von _[Deleted]_ (1. Oktober 2023 um 00:52)

  • Wenn jemand ne geniale Idee hat, wie ich eine Shelly.call() Warteschlange erstellen kann, ohne den Speicher bei über 20 aktiven Calls in den Streik zu schicken, dann her damit!

    Ehrlich gesagt habe ich mir darüber schon den Kopf zerbrochen, aber sobald die 25 aktive Calls-Grenze überschritten wird, wird mein Call-Cache-Objekt zu groß und das Script springt mit "Out of Memory" auf stopp. Ich dachte schon daran, ein Array anstelle von nem Objekt zu verwenden, aber das ist eher so, als ob man einen kleinen Wassereimer gegen einen Ozean verschüttet - es löst das Problem nicht wirklich.

    Also, wenn euch eine geniale Lösung einfällt, bin ich ganz Ohr und freue mich über jeden Geistesblitz von außen! 😄

  • Nachdem ich verschiedene Methoden ausprobiert hab, um mehr Calls gleichzeitig zu verarbeiten, gebe ich das vorhaben nun auf.

    Versucht hab ich, den Call Cache ins KVS zu leeren und den Call Cache in eine Event-Schleife zu leeren. Mehr ist mit nett eingefallen.

    Leider hat keines von beiden funktioniert. Im KVS kann man keine größeren Daten auf einmal speichern, und der Event-Ansatz führt dazu, dass der Shelly nach ein paar Minuten abstürzt.

    Wenn man die Calls() als externen Aufruf behandel, also als Tool für Code der noch net fest steht, ist es nicht möglich mehr zu verarbeiten als in den verfügbaren Memory passt.

    Ne Pause im UserScript ermöglich zwar endlose Calls, doch das war net mein Ziel, es sollte ja sowas wie ein Shelly.Call() Upgrade werden.

    Je nachdem wie viel Memory zur Verfügung steht, und wie groß die einzelnen Calls sind, sind zwischen 20 - 160 aktive Calls möglich.

    Hier sind einige Erkenntnisse aus meinen Versuchen:

    1. Objekte benötigen genauso viel Speicherplatz oder sogar weniger Speicherplatz als Arrays.

    2. Die Verarbeitung von Objekten erfordert weniger Rechenleistung als die Verarbeitung von Arrays.

    3. Events haben kein Wertlimit, aber wenn die Nachrichten > 500 Zeichen sind, kommt es oft zu Abstürzen.

    4. Events haben Vorrang vor Shelly.calls. Wenn der Shelly mit Events überflutet wird und gleichzeitig 4 Calls vorhanden sind, werden die 4 Calls zwar ohne Fehlermeldung aufgerufen, doch sie werden nie wirklich ausgeführt.

    5. Zu viele Events gleichzeitig führen zu einem hohen internen Time Offset, und der Shelly versucht ständig, diesen Offset auszugleichen.

    6. Wenn zu viele Events auf einmal auftreten, kommt es irgendwann zu einem Absturz. Früher (fw 0.14.x) wurden zu viele Events einfach verworfen.

    7. Falls der Shelly mehrmals abstürzt, wird automatisch ein Core Dump an einen Shelly Cloud Server gesendet.

    Hier sind zwei kleine Skripts, mit denen man gut abschätzen kann, wie viel Speicher im Skript zur Verfügung steht und ebenfalls Arrays mit Objekten vergleichen.

    Test Script Array:

    Code
    let stack = [];
    function stacking(a) {
    stack.push(a);
    }
    for (let i=0; i<200; i++) {
    stacking(['Switch.set', {on: true, id:0}, i]);
    print(i);
    }

    Test Script Object:

    Code
    let stack = {};
    function stacking(a,b,c) {
    stack['m'+c] = a;
    stack['p'+c] = b;
    stack['d'+c] = c;
    }
    for (let i=0; i<200; i++) {
    stacking('Switch.set', {on: true, id:0}, i);
    print(i);
    }

    Vielen Dank an ostfriese , der mir bei der Durchführung einiger Versuche geholfen hatte. :thumbup:

    11 Mal editiert, zuletzt von _[Deleted]_ (2. Oktober 2023 um 17:19)