Forkable FHEMWEB Extensions

Begonnen von rudolfkoenig, 12 September 2014, 07:50:59

Vorheriges Thema - Nächstes Thema

rudolfkoenig

Das funktioniert aber nur, wenn es sich um einen reinen Lese-Prozess (wie beim SVG erstellen) handelt, sonst setzt man Attribute/etc im Unterprozess, und der ueberlebende Haupt-Prozess hat keine Ahnung davon.

Wie sollten wir dieses Problem loesen?
Mein Vorschlag: man setzt in ${data}{FWEXT}{<PFAD>}{FORKABLE}, und plotfork wird dann automatisch angewendet, falls im URL Pfad auftaucht.

Dr. Boris Neubert

Hallo Rudi,

finde den Vorschlag gut. Rein interessehalber: welche Module gibt es, die in FW_Read Änderungen an Attributen/ Variablen/ etc. vornehmen?

Habe in 02_RSS.pm
$data{FWEXT}{$url}{FORKABLE} = 1;
hinzugefügt und eingecheckt.

Zum Testen in der Entwicklung folgende Zeilen in der fhem.conf:
define RSS RSS jpg localhost /Pfad/zur/Datei/namens/tinylayout
attr RSS refresh 5


Die Datei tinylayout beinhaltet:
rgb c0c0c0                      # HTML color notation, RGB
pt 18
date 25 470
pt 48                           # font size in points
time 20 525                     # time @ (0.1*width, 0.9*height)


Und im Browser aufgerufen wird die URL:
http://localhost:8083/fhem/rss/RSS.html

Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

rudolfkoenig

Hab FHEMWEB und SVG umgestellt, und damit getestet.
RSS habe ich nicht getestet, weil GD zu installieren mir jetzt zu zeitraubend ist (ging nicht auf Anhieb).

Alle Module nehmen Aenderungen vor, wenn man z.Bsp. im Detailfenster ein Attribut modifiziert, oder im Frontend ein SET durchfuehrt. FLOORPLAN ist z.Bsp. auch via FWEXT realisiert

Dr. Boris Neubert

Danke sehr, Rudi.

Getestet mit RSS und produktiv genommen.

Erster Eindruck: läuft wie geschmiert. Das Antwortverhalten auf der Konsole und im Webinterface ist hervorragend.

Werde noch den Bilderrahmen anwerfen, um die Last zu erhöhen, und melde mich dann mit den endgültigen Testergebnissen zurück, wenn die Installation einige Zeit gelaufen ist.

Viele Grüße
Boris

Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Dr. Boris Neubert

Hallo,

parallel ist parallel. Eine Seite in FHEMWEB mit vielen Plots reduziert dann die dem FHEM-Hauptprozess zur Verfügung stehende CPU-Zeit dramatisch. Beigefügter Patch (mit Doku :-) wertet das Argument von plotfork als denjenigen Betrag aus, um den der Nice-Wert der Kindprozesse gegenüber dem Elternprozess erhöht wird. Mit attr myFHEMWEB plotfork 10 geht dann auch die Load nicht mehr durch die Decke.

Viele Grüße
Boris

P.S.: Doof übrigens, dass RSS ein Gedächtnis braucht, was so nicht funktioniert...  :'(  Muss mir was überlegen.

Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

rudolfkoenig


Dr. Boris Neubert

Danke fürs Einchecken.

Ich habe mir ins Knie geschossen, da ich trotz meiner Nachfrage völlig ignoriert habe, dass Aufrufe des RSS-Moduls sehr wohl Variablen verändern (den Aufrufzähler sowie die laufende Nummer des Hintergrundbildes). Jetzt muss ich sehen, wie ich da rauskomme.

Nach längerer Lektüre von perlipc scheint mir folgende trickreiche Vorgehensweise minimalinvasiv umsetzbar. Bevor ich Dich mit einem Patch beglücke  ;) möchte ich zunächst Deine Gedanken dazu hören.

Vor dem fork in FW_Read() wird mit

pipe(READER,WRITER);

eine Pipe erstellt. Der Elter-Prozess merkt sich global je Kind-Prozess den READER und schließt den WRITER. Der Kind-Prozess merkt sich den WRITER und schließt den READER.

In SignalHandling() in fhem.pl wird das Signal CHLD nicht mehr ignoriert sondern es wird gewartet und aus dem READER gelesen:


$SIG{'CHLD'} = sub {
    $pid= wait;
    if($pid> 0) {
         Lies aus dem READER für den Kind-Prozess mit PID $pid und werte das Ergebnis mit eval() als Perl-Kode aus;
    }
}


Der Kind-Prozess kann dann seine Wünsche in den WRITER schreiben.

Viele Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

justme1968

boris,

schau mal hier http://forum.fhem.de/index.php/topic,18275.msg173732.html#msg173732

da gibt es den anfang einer sandbox Implementierung die forken und per pipe zwischen parent und child im beide richtungen kommunizieren kann.

das ganze ist noch lange nicht fertig aber im prinzip funktioniert es. man muss auf ein paar dinge achten. der patch  erlaubt neben deiner anwendung natürlich nich ein paar dinge mehr. wenn sich etwas in diese richtung entwickelt fände ich es schön keine modulspezifische einzelimplementierung zu haben sondern so eine globale sandbox oder ein zentrales nonBlockingCall das auch anderen modulen zur verfügung steht.

eine vielleicht kurzfristig einfachere lösung für dich könnte sein wenn du den geforkten SVG prozess einfach per telnet mit dem parent reden lässt. das könnte fhem ohne einen patch. ein beispiel dafür gibt es in BlockingCall.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

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

rudolfkoenig

@Boris: dein Vorschlag finde ich schon sehr speziell fuer dein Problem, ich wuerde stattdessen die vom andre auch erwaehnte Methode ueber Telnet verwendet, da kannst du mit { perlcode } auch direkt deine Variablen setzen. Musst nur sicherstellen, das ein telnet existiert, und dazu koennten wir die in BlockingCall schon implementierte Verfahren in eine eigene Funktion auslagern.

Als allererstes wuerde ich aber ueberlegen, ob ich diesen Aufrufzaehler brauche, das Bild kann ja auch einen Zeitstempel statt laufenden Nummer haben.

Dr. Boris Neubert

Danke, Andre und Rudi, für Eure Beiträge.

Ich liefere erstmal mehr Kontext mit, welche Gedanken meinem Beitrag vorausgingen.

Ich will die einfachst mögliche Lösung dafür, dass RSS bei jedem Aufruf zyklisch das zuletzt verwendete oder das nächste Element aus der Liste der vom Anwender vorgegebenen Bildern auswählt, abhängig davon, ob seit dem letzten Aufruf höchstens oder mehr als tmin Sekunden vergangen sind. Ich meine, dass sich RSS dazu die Nummer und den Zeitstempel merken muss. Derzeit geschieht dies in internen Variablen am Device. Ich könnte die Werte auf der Platte speichern (örgs) oder, wie auch vorgeschlagen, über einen Aufruf von fhem.pl <port> <perl> von hinten durch die Brust ins Auge aus dem geforkten Prozess in den Hauptprozess einspeisen. Mir schien die zweite Möglichkeit recht plump, aber sie ist meine Fallbacklösung, wenn wir nicht besseres finden.

Zunächst: welche Aufgaben wollen wir jeweils lösen?

1. Bei mir geht es darum, dass nebenläufige Plugins für FHEMWEB (RSS, SVG, ggf. andere) bei Beendigung Veränderungen im Hauptprozess auslösen können.
2. Bei der Sandbox geht es darum, mehrere FHEM-Instanzen abgeschottet nebeneinander laufen zu lassen, die bidirektional mit dem Hauptprozess kommunizieren.

Gemeinsam ist beiden Aufgaben, dass Kind-Prozesse mit dem FHEM-Hauptprozess kommunizieren.

  • Mein Vorschlag verwendet eine Pipe, Andres Sandbox verwendet ein Socketpair.
  • Ich lese aus der Pipe, nachdem der Kindprozess beendet wurde, Andres Sandbox kommuniziert laufend (habe noch nicht verstanden, wo das Hauptprozess-seitige Ende der Kommunikation ist).

Beide Ansätze sind m.E. vereinbar und wir könnten uns die Aufgabe stellen, einen Standard für bidirektionale Kommunikation zwischen Haupt- und Kind-Prozessen zu definieren. So verstehe ich Deinen, Rudis, zweiten Satz mit der Auslagerung.

Was ich mich frage: warum wurde in BlockingCall.pm der Weg über TCP/IP-Kommunikation mit TelnetPort gewählt. Wäre es nicht einfacher, eine Pipe oder ein Socketpair zu verwenden und im Hauptprozess das Hauptprozess-seitige Ende in der Hauptschleife (MAIN) transparent zu verarbeiten?

Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

justme1968

hallo boris,

deinen speziellen anwendungsfall könnte man auch ganz ohne ipc lösen in dem jeweils vor dem forken gezählt wird. z.b. über ein ${data}{FWEXT}{<PFAD>}{usageCount}. wenn rudi das nicht zu speziell ist sondern auch als statistik nützlich findet wäre das die einfachste lösung.

oder ein pre-fork hook ($hash->{preForkFn}) den fhem vor dem forken im modul jeweils aufruft. da könntest du vor dem forken einen counter inkrementieren und hast den jeweils aktuellen wert nach dem forken.


zu den unterschieden zwischen sandbox und deinem vorschlag:
ja die haupt intention ist eine andere. das ziel ist aber die basics die als grundlagen darunter legen so allgemein zu halten das sie einfach auch in modulen wieder verwendbar sind wie deiner anwendung, BlockingCall und bidirektionales FHEM2FHEM.

zu diesen basics zähle ich:
- aufsetzen der kommunikation zwischen parent und child. entweder nur in eine richtung oder in beide
- ein 'simples' protokoll
- eine zentrale stelle in fhem in der die nachritten zurück kommen, das protokoll ausgewertet wird und kommandos direkt ausgeführt oder an das zuständige modul weitergereicht werden
- das forken mit allen randbedingungen 'fhem konform' erfolgt

auf diese basics die auch von anderen modulen und zu anderen zwecken verwendet werden können und sollen setzt dann das sandbox modul auf das komplett gekapselt und eigenständig ist (sein soll).

das ganze könnte man in ein fhemIPC.pm modul auslagern das dann von BlockingCall und sandbox verwendet wird. die preForkFn könnte auch hier teil des api sein.


socketpair macht intern nichts anderes als zwei pipes zu liefern. zwei weil ich in beide Richtungen kommuniziere. wenn nur in eine richtung kommuniziert wird kann eine der beiden sofort wieder zu gemacht werden und das ergebnis ist eine pipe für eine richtung. oder man lässt sich von socketpair nur die eine pipe für die relevante richtung geben.

ob nach dem ende des kind prozesses gelesen wird oder während er noch läuft ist für das lesen an sich kein unterschied. es hängt nur von der programm logik ab. im falle eines zählers würde ich aber vermutlich auch direkt nach dem forken als erstes zählen weil sonst das verhalten von der größe des bildes abhängt. ist aber vermutlich im svg fall egal?


BlockingCall geht vermutlich deshalb über telnet weil es eigentlich ein hack ist/war mit dem rudi probieren wollte ob so etwas überhaupt geht ohne in fhem große änderungen oder infrastruktur zu haben.

gruss
   andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

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

Dr. Boris Neubert

Hallo Andre,

Zitat von: justme1968 am 13 September 2014, 11:12:18
deinen speziellen anwendungsfall könnte man auch ganz ohne ipc lösen in dem jeweils vor dem forken gezählt wird. z.b. über ein ${data}{FWEXT}{<PFAD>}{usageCount}. wenn rudi das nicht zu speziell ist sondern auch als statistik nützlich findet wäre das die einfachste lösung.

oder ein pre-fork hook ($hash->{preForkFn}) den fhem vor dem forken im modul jeweils aufruft. da könntest du vor dem forken einen counter inkrementieren und hast den jeweils aktuellen wert nach dem forken.

aus meiner Sicht spricht gegen beide Lösungsansätze, dass FHEMWEB zum Zeitpunkt des Forks das angesprochene Device gar nicht kennt. Die Extensions funktionieren so, dass für bestimmte URLs die Auslieferung der Antwort auf den HTTP-Get-Request an die Extension delegiert wird. Im Fall von RSS bestimmt dann zunächst eine Klassenfunktion anhand der URL, welches RSS-Device gemeint ist (Ermittlung des Device-$hash) und ruft dann die Funktion zur Auslieferung der Antwort mit dem $hash als Parameter auf.

Mit dem Rest Deines Beitrags gehe ich absolut konform.

Mal sehen, was Rudi meint.

Grüße
Boris

Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

justme1968

ok. verstanden.

der ansatz vor dem forken zu zählen und ohne ilc auszukommen sollte aber dann wieder gehen wenn du das forken selber unter kontrolle hast. also diesen teil aus einem potentiellen fhemIPC.pm selber aufruft.

wenn ihr das auch so seht würde ich als einen ersten schritt vorschlagen das forken (mit dem fhem nötigen drum rum) aus BlockinCall in eine eigene funktion auszulagern.

das wäre auch im OWServer und XBMC modul nützlich.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

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

Dr. Boris Neubert

Zitat von: justme1968 am 13 September 2014, 11:35:50
wenn ihr das auch so seht würde ich als einen ersten schritt vorschlagen das forken (mit dem fhem nötigen drum rum) aus BlockinCall in eine eigene funktion auszulagern.

zu meinem Verständnis: jedes Modul kann dann Kind-Prozesse mittels dieser Funktion forken gemäß eigener Logik. Ist das Drumherum die bidirektionale Socketkommunikation?

Ich habe mir gestern abend den Kode von FHEMWEB i.V.m. fork angesehen. Wie soll funktionieren, dass die Extension die Auslieferung der Antwort an den Client an einen Kind-Prozess delegiert ohne dass der FHEM-Hauptprozess davon nichts mitbekommt?

Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

justme1968

das drumherum wäre (konfigurierbar) die bidirektionale komunikation und vor allem das schliessen aller nicht benötigten filedescriptioren so wie es in BlockingCall passiert. alle stellen die fork direkt aufrufen lassen z.b. die verbindungen zu den usb devices und der db offen und verhindern das fhem sich per restart sauber neu starten lässt.


er hauptprozess (bzw der teil des Haupt prozesses der dann im child weiter läuft) muss insofern etwas davon mitbekommen als das er sich beenden muss statt weiter zu arbeiten.

den genauen Mechanismus hier zu müssen wir noch festlegen. z.b. über $data{FWEXT}{$url}{FORKABLE} in Verbindung mit einem check auf $$. z.b. so:
$data{FWEXT}{$url}{FORKABLE} = 1 -> fhemweb soll forken, wie für svg

$data{FWEXT}{$url}{FORKABLE} = 2 -> das modul forkt eventuell selber, vor dem aufruf $$ merken, wenn nach dem aufruf die gemerkte pid != $$ ist einfach beenden.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

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