[Bug]: Blockly "IDs vom Selector" erzeugt hohes eventLoopLag
I'm sure that
- [x] This issue is still present in the current beta version of this adapter
- [x] There is no other (open) issue with the same topic (use the search!)
- [x] This issue is not described in the adapter documentation / FAQ (read the docs!)
Script type
Blockly
The problem
Der Block "IDs vom Selector" wird standardmäßig mit dem Inhalt channel[state.id=*] eingefügt.
In meinem Script benutze ich folgenden Selector: channel[state.id=mihome-vacuum.0.rooms.*.mapIndex], der im Ergebnis alle 15 von insgesamt 108 Datenpunkten in diesem Pfad selektiert.
Problematisch dabei ist, dass beim Ausführen von diesem Selector der eventLoopLag der Javascript-Instanz auf über 2 Sekunden, teilweise sogar 17 Sekunden, ansteigt und das Bearbeiten des Selectors im Skript ca. 20 Sekunden dauert.
Ändert man den Selector auf state[id=mihome-vacuum.0.rooms.*.mapIndex], so verringert sich die Bearbeitungszeit des Selectors auf 9ms.
Ich halte das für einen Bug, da beide Selectoren eigentlich zum selben Ergebnis führen sollten.
Sollte es sich dabei um einen Fehler in der Anwendung handeln, so würde ich vorschlagen, die Voreinstellung von channel[state.id=*] auf state[id=*] zu verändern.
iobroker.current.log (in debug mode!)
No response
Version of nodejs
20.18.1
Version of ioBroker js-controller
7.0.6
Version of adapter
8.8.3
- Wie viele Objekte hat dein System in summe?
- Passiert das immer oder nur wenn das skript das erste mal diesen check macht (oder wird das Skript immer neu getriggert und jedes mal beendet?)
Die beiden selektoren haben schon eine andere bedeutung. der mit channel selektiert nur states die auch in einem channelliegen, der ohne macht dies nicht. Daher muss der mit channeln noch zusätzlich filtern.
Es ist korrekt das für ein generisches" nach einer ID filtern" eigentlich der Selektor mit channel "blödsinn" ist, man müsste überlegen war das so ist.
Mein System hat 34866 Objekte und 28836 Zustände. Das Script arbeitet mit Triggern und läuft somit dauerhaft. Innerhalb des Scripts gibt es 4 solcher Selektoren mit unterschiedlichem Inhalt, wobei 2 davon als Trigger fungieren, und zwei andere Datenpunkte für die Bearbeitung in einer Schleife zur Verfügung stellen. Der oben beschriebene Selektor ist der für die Bearbeitung in der Schleife.
Das Verhalten tritt in zwei Fällen auf:
- Neustart des Scripts
- Wenn genau die Funktion angetriggert wird, die den Selektor mit der Schleife beinhaltet.
Die beiden selektoren haben schon eine andere bedeutung. der mit channel selektiert nur states die auch in einem channelliegen, der ohne macht dies nicht. Daher muss der mit channeln noch zusätzlich filtern.
Dieser Unterschied war mir so nicht bekannt. Interessant ist aber, dass in beiden Fällen trotzdem ein Ergebnis geliefert wird, denn der oben gezeigte Selektor geht tatsächlich über Datenpunkte, die sich innerhalb von Channels befinden, der andere Selektor über Datenpunkte, die sich in Foldern befinden.
Es ist korrekt das für ein generisches" nach einer ID filtern" eigentlich der Selektor mit channel "blödsinn" ist, man müsste überlegen war das so ist.
Ich fände es gut, wenn man das irgendwie selbsterklärender machen könnte. Ich habe mich über Monate hinweg mit dem Fehler herumgeärgert und Fehlersuche betrieben. Lange Zeit ohne Ergebnis, weil die Zusammenhänge gar nicht so leicht zu erkennen waren. Letztlich war es reiner Zufall, dass ich einen anderen Selektor ausprobiert hatte und damit zur Lösung kam. Dieser Selektor führte auch dazu, dass der Javascript-Adapter ab und an, scheinbar ganz zufällig, abstürzte - das konnte ich jetzt im Nachgang erkennen.
Man kann in dem Baustein ja eintragen, was man möchte und benötigt, aber dass die Voreinstellung zu so einem Verhalten führt, ist ein wenig ärgerlich. Mein Vorschlag wäre state[id=*] als Voreinstellung, oder vielleicht sogar ein Drop-Down-Menü mit den möglichen Inhalten, sollte das technisch möglich und abwärtskompatibel sein.
Ich empfehle immer den Auswahl zu cachen.
const cache = {};
function getCachedStates(selector) {
if (cache[selector]) {
return cache[selector];
}
cache[selector] = [];
return new Promise(resolve => {
$(selector).forEach(id => cache[selector].push(id));
resolve(cache[selector]);
});
}
const ids = await getCachedStates('channel[state.id=mihome-vacuum.0.rooms.*.mapIndex]'); console.log(ids)
Abwer sollten wir das nicht im Adapter besser direkt tun? Könnten cache clearen wenn neue objhekte kommen oder gelöscht werden ode rggf auch prüfen und löschen.. ggf besser als die alternative? zumindestens bei den "teuren"?