Warten bis nichts mehr passiert

08/10/2012 - 17:12 von Matthias Hanft | Report spam
Hallo,

da versagen jetzt doch etwas meine Linux-Kenntnisse: Ich warte mit inotifywait
(dauerhaft mit --monitor), bis sich in einem Verzeichnis(baum) Änderungen ergeben,
und starte dann ein Programm, das aus dem überwachten Verzeichnis(baum) eine
HTML-Seite erzeugt (in einem bestimmten Format, das mit Apache-Bordmitteln
so nicht möglich wàre - da muß auch aus den einzelnen Dateien was rausgelesen
werden und so).

Das klappt soweit auch, allerdings kann's passieren, daß eine einzige Datei schon
mehrere Events schnell hintereinander erzeugt (viele "modify", mindestens zwei
"write_close"), und es kann ebenso passieren, daß z.B. mehrere Dateien auf einen
Schwung in das Verzeichnis geladen werden; dann würde es natürlich reichen, die
HTML-Seite *einmal* zu erzeugen und nicht nach jeder Datei einzeln (N-mal inner-
halb von Sekundenbruchteilen).

Ich habe jetzt schon an einen crobjob alle fünf-oder-so Minuten gedacht, aber a)
würde der auch dann die Seite überflüssigerweise neu erstellen, wenn sich gar
nichts geàndert hat, und b) möchte ich die Seite eher nach fünf Sekunden als
nach fünf Minuten aktualisiert haben.

Dann hatte ich gedacht, könnte das inotifywait z.B. ein Flag (als Datei in
/tmp) setzen, der Cronjob könnte jede Minute laufen, aber die HTML-Seite nur
dann erzeugen, wenn das Flag gesetzt ist (und danach das Flag löschen). Gefàllt
mir aber auch nicht so recht, weil es dann a) im Worst Case immer noch bis zu
einer Minute dauern kann, bis die Seite aktualisiert wird (das ist lang, wenn
man drauf wartet, daß die Zeit rum geht), b) habe ich dann jede Minute einen
cron-Eintrag im syslog, und c) könnte es passieren, daß das Flag quasi gleich-
zeitig gesetzt und gelöscht wird und die letzten Änderungen dadurch nicht
erkannt werden.

Was ich also bràuchte, wàre ein Mechanismus, der drauf wartet, daß das inotify-
wait fünf Sekunden lang nichts mehr sagt und dann den Update-Prozess startet.
(Sollte derweil das inotifywait doch noch etwas sagen, müßte das gespeichert
und der Update-Prozess danach halt nochmal gestartet werden, damit keine Ände-
rungen verlorengehen.)

Ich könnte das natürlich auch in einem selbergeschriebenen C-Programm machen,
das die inotifywait-Ausgaben einliest (oder sogar direkt inotify(2) aufruft,
wobei ich mich dann wohl allerdings um "--recursive" selber kümmern müßte)
und in einer Schleife mit sleep die Sekunden seit der letzten Ausgabe mitzàhlt.
Aber a) glaube ich nicht so recht, daß sich das nicht auch mit Linux-Bordmit-
teln erledigen ließe (evtl. irgendwas mit "at"?), und b) hàtte ich dann mit
der sleep-Schleife ja wieder Polling, das ich mit dem inotify ja gerade ver-
meiden wollte.

"inotifywait -t" hàtte zwar eine àhnliche Funktionalitàt, geht aber auch
nicht, weil ich anfangs ja auch unendlich lange warten können muß. Hmmm...
oder (in einer àußeren Schleife) ohne "--monitor" und "-t" (dann kann man
erst mal unendlich lange warten, bis überhaupt irgendwas passiert), und
dann in einer (inneren) "Jetzt-ist-was-passiert"-Schleife so oft mit "-t 5",
bis der Exit Code 2 rauskommt? Erscheint mir aber etwas "von hinten durch
die Brust ins Auge"?! Oder ist das genau *die* Lösung?

Wie würdet Ihr das lösen, möglichst mit Linux-Bordmitteln und ohne Polling?

Danke & Gruß Matthias.

PS: Eine ganz andere Alternative wàre natürlich, die Seite einfach bei jedem
Abruf "live und online" dynamisch zu erzeugen. Das würde dann allerdings
doch ein paar Sekunden dauern, und da sich in dem überwachten Verzeichnis
wesentlich seltener was àndert als die Seite abgerufen wird, würde da bei
jedem Abruf unnötige CPU-Last erzeugt, um Dateien einzulesen, bei denen
sich gar nichts geàndert hat. (Ok, da könnte inotify auch wieder ein Flag
setzen, und das PHP-Skript schaut beim Abruf nach, ob es die Seite ggf.
neu erzeugen muß oder nicht. Dann ist aber immer der erste, der die Seite
nach einer Änderung abruft, der Dumme, weil er lànger warten muß als alle
anderen) :-)
 

Lesen sie die antworten

#1 Ralf Döblitz
08/10/2012 - 20:23 | Warnen spam
Matthias Hanft schrieb:
[...]
Ich könnte das natürlich auch in einem selbergeschriebenen C-Programm machen,
das die inotifywait-Ausgaben einliest (oder sogar direkt inotify(2) aufruft,
wobei ich mich dann wohl allerdings um "--recursive" selber kümmern müßte)
und in einer Schleife mit sleep die Sekunden seit der letzten Ausgabe mitzàhlt.
Aber a) glaube ich nicht so recht, daß sich das nicht auch mit Linux-Bordmit-
teln erledigen ließe (evtl. irgendwas mit "at"?), und b) hàtte ich dann mit
der sleep-Schleife ja wieder Polling, das ich mit dem inotify ja gerade ver-
meiden wollte.



Das ist schon fast einer der richtigen Wege. ;-)

Wenn du Polling&Sleep durch ein SIGALRM ersetzt, dann hast du eine
Lösung schon fast. Ich würde das aus Bequemlichkeit mit Perl machen,
aber wenn du in C fit bist, dann dürfte das auch trivial sein:
Einfach bei jedem gelesenen Event den Alarm auf die gewünschte Zeit
(z.B. 5 Sekunden) setzen, wenn vorher ein neuer Event kommt wird der
Alarm wieder auf einen spàteren Zeitpunkt gesetzt. Tut sich dann diese
Zeit lang nichts so bekommt dein Program ein SIGALRM und du kannst dein
Generator-Programm starten.

Anderer (IMHO schönerer) Ansatz: in einem Programm mit select und
timeout auf Ausgaben von inotifywait warten, bei timeout dann das
Generator-Programm anstarten. Mittels zusàtzlichem Flag diee Aktion nur
dann durchführen, wenn es Änderungen gab (d.h. wenn du tatsàchlich auch
Input gelesen hattest).

Ralf
Eine GABELN heißt im Fido nàmlich "Echo", weil da reingegatete Artikel
öfters mit anderer Message-ID wieder rauskommen.
  – Oliver B. Warzecha

Ähnliche fragen