DBLog asynchron / nonblocking GET?

Begonnen von Thyraz, 03 März 2020, 23:32:04

Vorheriges Thema - Nächstes Thema

Thyraz

Hallo liebe Loggenden. :)

Ich arbeite unter anderem gerade an einem Tablet-UI Widget auf Basis von Chart.js, da ich eine eigene Widget-Sammlung erstellen will um ein einfach / schnell konfigurierbares Frontend zu ermöglichen, welches einen modernen Look im Stil von OpenHab oder Home Assistant bietet.
Also weniger hochpersonalisiertes Grid für ein Wandtablet wie das normale TabletUI, dafür mehr wie FHEMWeb ohne Administrationsmöglichkeiten für den Rest der Familie und mit etwas Eyecandy.

Beim Thema Charts beiße ich mir gerade aber ein wenig die Zähne aus, da größere Datenabrufe mit massiven Freezes des SmartHomes quittiert werden.

Sehe ich es richtig, dass bei DBLog auch im asynchronen Modus die GET Aufrufe weiter synchron/blockierend sind?
Jedenfalls kann ich mit dem Abruf der Messwerte eines Temperatursensors über ein ganzes Jahr mein FHEM locker eine Minute lahmlegen. ;)

Besteht die Hoffnung, dass:
a) ein Get von Logdaten (neben DBLog wäre ja auch FileLog interessant) in FHEM so asynchron realisiert werden kann, dass es die bisherige Funktionalität nicht beeinflusst oder sonstige fiese Seiteneffekte hat?
b) das ganze dann beim Abruf über einen HTTP Aufruf mit XHR=1 auch funktioniert? Ich muss die Daten ja aus dem Widget irgendwie von Fhem anfordern.

Falls a) nicht klappt auch gern als seperaten Get Befehl. ;)

Ich kann jetzt natürlich auch anfangen eine Middleware zu schreiben die der Nutzer dann parallel zu FHEM installieren muss und die dann die Daten direkt aus MYSQL zieht, aber eigentlich kann das ja nicht das Ziel sein.
FHEM bietet so schöne Funktionalitäten mit der ähnlichen Syntax / Ausgabe für FileLog und DBLog, sowie mit Logproxy auch hervorragende Werkzeuge um die Logdaten on-the-fly zu manipulieren oder mit Live-Daten anzureichern.

Mit einem asynchronen Abruf wäre es z.B. kein Problem große Datenmengen wie eine Temperatur-Jahresansicht abzurufen und die Daten dann ggf. mit einer Aggregationfunktion so auszudünnen, dass man nur die stündlich gemittelten Werte im Chart anzeigt.
Lädt dann eben ein paar Sekunden, aber wenn Frontend und FHEM das nonblocking handhaben, zeigt man solange eben einen Loading-Indicator an...

Aktuell hab ich selbst beim Abruf der Daten eines Monats für mehrere Temperatursensoren parallel in einem Chart Bauchschmerzen wenn der Abruf knappe 2 Sekunden dauert (bei einem Raspberry dürfte das ein Vielfaches betragen), da solche Freezes im falschen Moment, z.B. wenn ein Licht durch Bewegungsmelder angehen soll die Akzeptanz des SmartHomes extrem schmälern...

Wie ist das denn bei FHEM internen Plots mit Plotfork?
Ist der Datenabruf hier genauso synchron und blockiert das System (da nur das SVG Zeichnen async ist), oder gibt es das Problem hier nicht?

Würde mich freuen wenn man den einen oder anderen der an diesen Modulen arbeitet hierfür begeistern könnte, da Loggen ja nicht nur den Sinn hat die Festplatten zu füllen.
Die wahre Freude daran ist ja die Visualisierung / Auswertung. :P
Fhem und MariaDB auf NUC6i5SYH in Proxmox Container (Ubuntu)
Zwave, Conbee II, Hue, Harmony, Solo4k, LaMetric, Echo, Sonos, Roborock S5, Nuki, Prusa Mini, Doorbird, ...

DS_Starter

#1
Nabend,

hatte deinen Thread schon gesehen.  :)

ZitatSehe ich es richtig, dass bei DBLog auch im asynchronen Modus die GET Aufrufe weiter synchron/blockierend sind?
Ja, siehst du (fast) richtig. Der asynch Modus bezieht sich auf Schreibvorgänge. Die Get-Aufrufe über die sub DbLog_Get sind für sich genommen blockierend.

ZitatWie ist das denn bei FHEM internen Plots mit Plotfork?
Ist der Datenabruf hier genauso synchron und blockiert das System (da nur das SVG Zeichnen async ist), oder gibt es das Problem hier nicht?
Der Aufruf über SVG ist nicht blockierend sofern man "plotfork" im global eingestellt hat. Rudi führt in diesem Fall ein fork aus bzw. benutzt inzwischen auch BlockingCall wenn ich mich nicht irrre.

Also das heißt man muss den Werteabruf per Blockingcall ausführen und die Daten in die Grafik einfügen wenn sie geliefert wurden. Im Prnzip mache ich das im DbRep in so gut wie allen Funktionen ebenso. D.h. ein "fetchrows" holt die Daten non-blocking aus der DB und stellt sie dar wenn sie (im RAM) vorliegen.

So etwas müsstest du auch verwenden. Eigentlich könntest du dein SQL-Statement dem Befehl sqlCmd im DbRep übergeben bzw. der entsprechenden DbRep-Funktion. Eine Herausforderung ist in jedem Fall die Vorgehensweise zur Synchronisierung des asynchronen Datenabrufs mit den Abläufen in deiner Applikation. Da muss man etwas Hirnschmalz reinstecken.

LG,
Heiko 
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

rudolfkoenig

ZitatDer Aufruf über SVG ist nicht blockierend sofern man "plotfork" im global eingestellt hat. Rudi führt in diesem Fall ein fork aus bzw. benutzt inzwischen auch BlockingCall wenn ich mich nicht irrre.
- falls ein Modul sich in $data{FWEXT} eingetragen hat und FORKABLE gesetzt hat, dann profitiert es von plotfork.
- falls gewuenscht, kann ich fuer FileLog Get einen Wrapper schreiben.
- BlockingCall ist/war eine Sackgasse und SVG spezifisch, sollte irgendwann wieder entfernt werden.

DS_Starter

Guten Morgen,

Zitatfalls ein Modul sich in $data{FWEXT} eingetragen hat und FORKABLE gesetzt hat, dann profitiert es von plotfork.
Das ist eine interessante Info Rudi. $data{FWEXT} ist soweit klar, aber wie/wo genau ist FORKABLE zu setzen ?

ZitatBlockingCall ist/war eine Sackgasse und SVG spezifisch, sollte irgendwann wieder entfernt werden.
Kannst du ein wenig erläutern was genau du damit meinst ? Nur damit man es richtig einordnen kann.

LG,
Heiko
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

rudolfkoenig

#4
Zitatwie/wo genau ist FORKABLE zu setzen ?
Bei SVG wird es so gesetzt:  $data{FWEXT}{"/SVG_showLog"}{FUNC} = "SVG_showLog";
  $data{FWEXT}{"/SVG_showLog"}{FORKABLE} = 1;



ZitatKannst du ein wenig erläutern was genau du damit meinst ?
Fuer SVG ist <embed> nicht mehr zeitgemaess. Mein erster Versuch es ohne <embed> zu parallelisieren war in FHEMWEB.pm per BlockingCalls die SVGs zu berechnen, und erst im letzten Callback die komplette HTML-Seite (inkl SVGs) zurueckzuschicken. Leider schickt Chrome nach 90 (manchmal 60?) Sekunden die Anfrage nochmal, wenn solange nichts kommt, was bei Seiten mit vielen Jahreslogs zu Chaos fuehrt.

Viel einfacher/problemloser ist die SVGs einzeln per JavaScript/XHR abzuholen, und sie im Browser in die Seite einzufuegen, das wird mit plotEmbed=2 aktiviert.
Die BlockingCall Variante wird mit plotFork=1 (und plotEmbed=0, Voreinstellung) aktiviert.

Demnaechst wird plotEmbed=2 die Voreinstellung sein.

DS_Starter

Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

Thyraz

Vielen Dank euch beiden schonmal für rege Diskussion. :)

Ja, an sich betrifft das nicht nur DBLog, sondern auch Filelog und womöglich auch LogProxy.

Es wäre daher unglaublich schön, wenn man für das nicht-blockierende Auslesen von Logdaten nicht auf andere Module wie DbRep (daran hatte ich auch sofort gedacht als die Problematik aufkam ;)) nutzen müsste oder bei FileLog notfalls sogar selbst die Logfile parsen.
Man erfindet damit ja irgendwie das Rad neu.

Mir fehlt leider ein wenig das tiefe interne Verständis wie in FHEM die Rückgabe von Forks zurück in den Mainprocess erfolgt, und wie der dann die Rückgabe an den Caller übermittelt.
Schaffe es daher auch nicht aus euren letzten Posts herauszulesen ob da schon eine Antwort auf diese Frage steckt.  :P

Ich rufe in meinem Code ja sowas auf:

http://<fhem-ip>:<port>/fhem/?cmd=get DbLog history - 2020-03-04_00:00:00 2020-04-04_10:00:00 Thermometer:humidity&fwcsrf=csrf_blablabla&XHR=1


Der Request wartet dann bis FHEM irgendwas antwortet, das so aussehen könnte:
Zitat
2020-03-04_00:24:04 38.51
2020-03-04_01:30:50 38.77
2020-03-04_07:35:32 40.12
2020-03-04_07:53:49 39.23
2020-03-04_09:23:32 38.72
2020-03-04_10:33:59 38.28
#Thermometer:humidity:::

Jetzt also die Frage ob es überhaupt möglich ist das in Modulen wie FileLog oder DbLog zu implementieren,
dass sie (evtl. über einen Parameter oder Attribut gesteuert) solche Logabfragen über einen Fork starten und der hauptprozess dann über die Antwort informiert wird und den Request entsprechend beantwortet?

Oder fehlt da Funktionalität an der FHEM Basis?

Und wenn es geht, ist das gewollt und will sich jemand den Schuh anziehen? ;)
Ich denke es wäre auf jeden Fall ein Gewinn Logdaten nicht nur blockierend abfragen zu können, da das Verzögerungspotential eben durchaus groß ist...

Die letzte Überlegung wäre noch:
Ist es gesund selbst kleinere Logabfragen über einen Fork auszuführen oder bekomm man hier schnell Speicherprobleme bei vielen parallelen Charts auf einer Seite.

Sollte das eher Usergesteuert sein, macht es evtl. Sinn das Ganze NUR in LogProxy zu implementieren statt in FileLog und DbLog?
Es agiert ja sowieso schon als Vermittler bei komplexeren Anfragen und durch die Syntax mit Optionen etc. wäre hier ein Flag für Async oder nicht recht einfach abzubilden.
Der Nutzer müsste bei größeren Datenabfragen gezielt auf LogProxy wechseln.



Fhem und MariaDB auf NUC6i5SYH in Proxmox Container (Ubuntu)
Zwave, Conbee II, Hue, Harmony, Solo4k, LaMetric, Echo, Sonos, Roborock S5, Nuki, Prusa Mini, Doorbird, ...

rudolfkoenig

Alternativ implementiere ich in FHEMWEB ein "forked_cmd" CGI Option, was den Befehl in einem geforkten Prozess abarbeitet, bin aber unsicher, ob DbLog damit zurechtkommt. Aber das Problem haette eine Implementierung ueber logProxy oder direkt in DbLog auch.

Forken ist leider nicht problemlos, weil Linux zu viel Speicher fuer Eventualitaeten reserviert.
Ich kenne bisher nur die systemweite Option das zu aendern, mir waere was fuer den Prozess selber lieber.
Wir koennten auch (fuer diesen begrenzten Zweck) mit Threads experimentieren, habe damit in perl noch keine Erfahrung.

DS_Starter

Den Vorschlag von Rudi bezüglich der CGI finde ich gut. Ich denke wir finden dann auch einen möglichen Weg DbLog dafür fit zu machen. Ich hatte kürzlich bezüglich CGI bei meinem SSChat Modul einige Erfahrungen sammeln können.
Threads kenne ich allerdings auch nicht, d.h. wäre ebenfalls komplett Neuland.
Der CGI Weg hätte m.M. nach auch den Vorteil dass du uniformes Interface für deine Applikation zur Verfügung hättest.
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

Thyraz

Gefällt mir auch sehr gut der Vorschlag. :)
Fhem und MariaDB auf NUC6i5SYH in Proxmox Container (Ubuntu)
Zwave, Conbee II, Hue, Harmony, Solo4k, LaMetric, Echo, Sonos, Roborock S5, Nuki, Prusa Mini, Doorbird, ...

justme1968

ja. das ganze an einer zentralen stelle zu implementieren ist die einzig vernünftige variante. so profitieren alle backends davon. aber ohne threads. das geht nicht in allen perl versionen und ist noch viel schwieriger zu debggen als eine multi prozess version.

wie gut das mit dblog geht kommt auf einen versuch an. da es hier um das reine lesen geht sollte es eigentlich zumindest genau so gut gehen wie das aktuelle plotfork. sqlite muss z.b. im child neu geöffnet werden. wir haben ja damals eine weile gebraucht bis das ging.

eine mögliche ergänzung zur optimierung: man könnte einen hook in der implementierung vorsehen und wenn die db (oder das jeweilige backend modul) es unterstütz könnte man statt dem fork dann intern diese variante über nonblocking read oder ähnliches verwenden. ob der aufwand lohnt weiss ich nicht.

ich bin im falle von speicher mangel immer geneigt in die hardware zu investieren und habe kein schlechtes gewissen einem anwender zu sagen das für ein bestimmtes neues feature und bei abfrage von grossen datenmengen ein x jahre altes system halt nicht mehr reicht.

unabhängig von einer konkreten umsetzung: hat schon mal jemand gemessen wo die zeit den wirklich genau verbraten wird?
- beim abfragen der db bzw. des logs, hier wäre forken vermutlich das einfachste
- dem aufbereiten der daten danach, hier könnte man häppchenweise arbeiten ohne zu forken,
   man müsste aber alle backend module einzeln anafassen, fork ist vermutlich einfacher
- dem senden ans frontend: hier würde das asynchrone schreiben schon helfen

und noch etwas fällt mir gerade ein: man könnte eventuell auch automatisch eine grosse anfragen in mehrere kleine aufteilen, häppchenweise verarbeiten und dann die antworten jeweils nacheinander ans frontend schicken. das würde das forken spaaren und eventuell sogar den speicherbedarf minimieren. je nach verarbeitung der daten sind aber eventuell sind die 'anschlussstellen' nicht sauber
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Zitatunabhängig von einer konkreten umsetzung: hat schon mal jemand gemessen wo die zeit den wirklich genau verbraten wird?
Vor 5-6 Jahren (als ich vorhatte SVG.pm in JavaScript nachzubauen), habe ich das gemessen: Fuer ein Jahresplot mit mehreren Linien aus der gleichen Datei hat FileLog ca 40%, und SVG etwa 60% benoetigt. Das haengt aber auch vom Filter, Dateiinhalt und Struktur, usw. ab.
Das Versenden der Daten ueber FHEMWEB laeuft seit laengerem asynchron, ueber addToWriteBuffer.

herrmannj

im Prinzip geht ja schon viel (alles?)

fwext kann forken (plotfork ist vielleicht etwas unglücklich als Name) und das kann die CGI komplett übernehmen. Und innerhalb des forks kann man sogar häppchenweise zurückgeben, allerdings muss man es selbst implementieren.

Ich denke das einige module die bereits bestehenden Möglichkeiten nicht ausreichend nutzen. Fairerweise ist die Übergabe an SVG mMn nicht optimal. Da würde ich den Weg der Client Darstellung angemessener sehen (also FWEXT liefert JSON an Script.) Das ist dann aber eben wieder eine andere Baustelle.

rudolfkoenig

Ab sofort wird beim gesetzten XHR=1 und asyncCmd=1 der Befehl in FHEMWEB in einem geforkten Prozess abgearbeitet, was nach Schreiben des Ergebnisses die Verbindung schliesst.

Folgender Befehl dauert auf meinem Rechner ca 4 Sekunden, liefert 3.5MB an Daten, aber blockiert FHEM nicht:wget -qO - 'http://localhost:8083/fhem?cmd=get outlog CURRENT - 2019-01-01_00:00:00 2019-12-31_23:59:59 4:out1.*:0:&XHR=1&asyncCmd=1&fwcsrf=csrf_701238297902474' | gzip -d > out.1

Ohne asyncCmd wird FHEM blockiert.

Zur Klarstellung: ich habe nicht, wie oben erwaehnt, ein foked_cmd implementiert, die gleiche Funkionalitaet wird mit der zusaetzlich gesetzten asyncCmd=1 erreicht.

Thyraz

Ich wünschte ich könnte gleich ein paar hundert "Gefällt mir" auf einmal abgeben. :)

Das funktioniert nicht nur wunderbar mit FileLog, sondern auch mit DBLog und logProxy.
Keine Ahnung ob es da unter euch schon Abstimmung gegeben hat, sonst scheint es out of the box zu laufen.

Ergebnisse kommen alle durch, Freezes bleiben aus und auch perfmon hat daher nichts zu meckern. ;)

Mal wieder ein schönes Beispiel wie in FHEM schnell und unkompliziert für Lösungen gesorgt wird.
Danke euch allen für die Diskussion und natürlich Rudi für die Umsetzung.
Fhem und MariaDB auf NUC6i5SYH in Proxmox Container (Ubuntu)
Zwave, Conbee II, Hue, Harmony, Solo4k, LaMetric, Echo, Sonos, Roborock S5, Nuki, Prusa Mini, Doorbird, ...