# SH - Script soll unter Unix Zeit auslesen und per CGI ausliefern



## Lukasz (15. Dezember 2006)

Hallo Liebes Forum

Ich brauche ein SH Script. Bzw. Ich muss mir eins bauen, welches unter Unix eine Uhrzeit aus einer Datenbank liest (sagen alle 30 Sekunden 1 Mal). Das Script müsste jede Sekunde von dieser Zeit 1 Sekunde abziehen. Es sollte die Möglichkeit haben, per CGI abgefragt zu werden.

Also ich bin ein PHP Flash Mensch. Habe schon Kleinigkeiten mit SH geübt, ist aber schon lange her. Ich möchte auch keine fertigen Scripte von euch. Viel eher brauche ich Unterstützung, um das zu realisieren zu können.

*Technisches:*
Ich schreibe per Cronjob PHP Script (Unix Crontab) jede Minute eine bestimmte Zeit in die MySQL Db (Unix Timestamp beim einschreiben + Anzahl Sekunden die ablaufen sollen). Dabei handelt es sich um Sekunden dir praktisch rückwärts aus Null runterlaufen. 

Eine Flash Datei braucht die Information andauernd, wiviel Zeit noch übrig ist. Also dockte die Flash Datei bislang an eine PHP Datei:

```
<?
$basedir = '/var/www/vhosts/xhost/httpdocs';
chdir($basedir);

include('functions.php');
database_connect();

$anfrage = mysql_fetch_assoc(mysql_query("SELECT * FROM `ifc_rounds` LIMIT 1"));

echo '&runde='.$anfrage['runde'].'&status='.$anfrage['status'].'&stamp='.time().'&restzeit='.($anfrage['ende'] - time() < 0 ? 0 : $anfrage['ende'] - time()).'&last='.$anfrage['zahl'];
?>
```

Alle Flashfilmchen müssen alle 5 Sekunden daran docken. Und zack ist der Server auf Grund Überlastung zusammengebrochen. DB überlastet.

Genau dies soll nun ein kleines Programm erledigen 2 Zugriffe pro Minute auf die DB etc. Es soll die Zeit auslesen, und in eine Systemvariable schreiben. Ein andere CGI SH Script soll auf diese Systemvariable zurückgreifen und einfach nur die Restzeit ausliefern.

Wer kann mir folgenden Rat geben.

-SH wie lese ich am schnellsten eine DB aus, und wie stelle ich sicher, dass dies alle 30 Sekunden geschieht?
-Wie schreibe ich die Zeit in eine Systemvariable pro Sekunde subtrahieren bis eben 0 ist?
-Wie lese ich die Systemvariablen aus.


Dann hätte ich noch die Frage, wie kann ich das Programm unter UNIX beim Start des Servers automatisch ausführen lassen?

Ich weiß, ist viel gefragt, aber jeder Hinweis wir mir helfen!

Oder hat einer einen besseren Vorschlag, für mein Vorhaben?


----------



## RedWing (17. Dezember 2006)

Hallo,

mal ne ganz blöde Frage:


> ch brauche ein SH Script. Bzw. Ich muss mir eins bauen, welches unter Unix eine Uhrzeit aus einer Datenbank liest
> ...
> Genau dies soll nun ein kleines Programm erledigen 2 Zugriffe pro Minute auf die DB etc. Es soll die Zeit auslesen, und in eine Systemvariable schreiben. Ein andere CGI SH Script soll auf diese Systemvariable zurückgreifen und einfach nur die Restzeit ausliefern.



Wenn du in php eh schon fit bist, wieso schreibst du das Abfrageprogramm nicht
auch in php oder gar perl? Damit lässt sich doch eine Datenbankverbindung viel
eleganter lösen als wie mit einem shell skript, wenn das überhaupt möglich ist...

Gruß,
RedWing


----------



## Dr Dau (17. Dezember 2006)

Hallo!

Das Problem ist dass die kleinste Zeiteinheit bei einem Cronjob 1 Minute ist.
Da die Datenbank aber im 30 Sekundetakt abgefragt werden soll, müsste das Script eigentlich in einer Endlosschleife laufen.
Fragt sich nur wie lange es dauert bis sich das Script aufhängt (oder sonst was passiert).
Daher würde ich das Script im Minutentakt per Cronjob neu "anstossen".
Vorteil daran ist es, wenn das Script z.b. durch eine fehlgeschlagene Datenbankabfrage abbricht (warum auch immer), wird es nach spätestens 1 Minute neu gestartet.

Was dass "1 Sekunde abziehen" betrifft, könnte man dieses sicherlich (in PHP) mit sleep() realisieren.

Auf jedenfall wird jede scriptbasierte Lösung serverlastig sein..... wenn es nicht sogar zu einer Überlastung führt.
Ob es auch bei einem ausführbaren rogramm der Fall währe, weiss ich nicht..... ich denke aber schon.

Gruss Dr Dau


----------



## RedWing (17. Dezember 2006)

Hallo,

wieso sollte man den Umweg über einen Cronjob gehen?
1.) Gibt dir keiner eine Garantie das der Cron Daemon ewig läuft
2.) hat man so zusätzlich overhead, da der Interpreter alle Minute neu 
angeschmissen werden muss
und 3.) alle Minute eine neue Datenbankverbindung aufgebaut werden muss.



> Da die Datenbank aber im 30 Sekundetakt abgefragt werden soll, müsste das Script eigentlich in einer Endlosschleife laufen.
> Fragt sich nur wie lange es dauert bis sich das Script aufhängt (oder sonst was passiert).
> ...
> Vorteil daran ist es, wenn das Script z.b. durch eine fehlgeschlagene Datenbankabfrage abbricht (warum auch immer), wird es nach spätestens 1 Minute neu gestartet.



Wenn die Datenbankabfrage einmal abbricht sehe ich das imho nicht so schlimm, 
da dann spätestens im neuen Schleifendurchlauf nach 30 Sekunden die 
Datenbankabfrage erneut gestellt wird.

Aber eventuell sollte man einfach mal alle 2 Versionen (also mit Cronjob und ohne)
ausprobieren und testen welche der beiden Varianten sich unter Belastung 
des Servers besser verhält.

Gruß,
RedWing


----------



## Lukasz (18. Dezember 2006)

Also vielen Dank erst einmal für die vielen Reaktionen. Vielleicht erkläre ich etwas näher und genauer, was ich realisieren muss.

Ich habe ein wichtiges System welches zu einer bestimmten Zeit Buchungen entgegen nehmen muss. Diese Buchungen werden von einem Spiel aus welches als Flash Film ausgegeben wird abgegeben. Nun geht es mir weniger um die Abgabe der Buchungen, aber es geht darum, in welche Runde diese Buchungen kommen. 

So dauert eine Spielrunde beispielweise 90 Sekunden (nur ein Beispiel). Ein Cron würde also wie folgt vorgehen.

1 Prüfung 0:00 Runde beginnt
2 Prüfung 0:01 Runde gerade mal 60 Sekunden aktiv
3 Prüfung 0:02 Runde wird beendet leider 30 Sekunden zu spät als geplant, aber immer hin.

Also das mit der Verspätung habe ich wie hier schon bereits besprochen wurde durch ein sleep() in php realisiert. Bzw while() schleife mit sleep(1) Anweisung.

Insoweit funktioniert das Script 1A! Nur leider möchten auch die derzeit bis zu 120 Spieler gleichzeitig an das System docken, um abzufragen, wieviel Zeit noch übrig bleibt, bist die Runde zu Ende ist. Oder aber gar, ob gerade eine Runde ausgelost wird, und garnicht gebucht werden kann.

Da bedankt sich natürlich der Datenbankserver über 120 Connects und 120 Querys alle 5 Sekunden, und bricht zur Folge vollständig zusammen. Mit einem Werkezeug schaltet er den Port ab, um einer Überlastung standhalten zu können.

Nun freuen sich die User. Die Flash Datei steht auf _root.stop() und gibt die Fehlermeldung 'Keine Verbindung zur Datenbank aus'!

Aus diesem Grund habe ich an folgende Lösung gedacht. Man müsste die Zeit irgendwo temporär zwischenspeichern, damit alle die die Restzeit wissen möchten, keine einzige Datenbankabfrage benötigen. Einzig das Programm selbst soll einmal alle 30 Sekunden die DB fragen. Per Cronjob nicht machbar. Per PHP viel zu instabil. 

Genau das ist leider mein Problem.

Wie sieht es aus, ich habe erfahren, dass PHP Seiten Cache kann. Wäre das sinnvoll, um alle unnötigen Abfragen von der Datenbank fern zu halten?

So wie eben oben beschrieben, habe ich ca. 5 Prozesse die von PHP aus an den Server gebracht werden müssten. Ganz gleich mit welcher Methode. Ich habe das berechnet. Der Server selbst bräuchte 0,1% von dem was an Userabfragen unnötig zusammenläuft. Deshalb kämpfe ich mich durch verschiedene Programmiersprachen, das irgendwie mehr oder weniger Sinnvoll zu bewältigen.

Übrigens gegen einen Scriptabbruch habe ich mich wie folgt geschützt. Ein Controlcron läuft alle Minute. Jeder Cron oder jedes Programm welches läuft, speichert ständig beim Ablauf seinen unix timestamp in eine txt.datei ab. der Controlcron prüft die Dateien. Findet er eine txt Datei, welche einen zu alten Stamp beinhaltet, wir zur folge dieses Script neu aufgerufen. Funktioniert alles und ist bereits über Jahr lang im Einsatz, hat auch noch nie Probleme gemacht.

*Folgendes Schema habe ich:*
Es gibt ein Verzeichnis namens *Dienste*
Dort liegen einzelne PHP Scripts, die jeweils eine Aufgabe zu tun haben vor. Nichts anderes wie include() Scripts aus der Webprogrammierung, nur eben für den Internen Ablauf. Man draf diese Scripte nur nicht per include() abrufen, sondern am Anfang in einer Variable schreiben und dann mit eval() bahandeln!

Dann gibt es ein Verzeichnis das den Namen *Aufgaben* trägt.
Es führt Standartroutinen durch. Als Beispiel kann ich Beispielweise das ermitteln des Gewinners der Aktuellen Runde nennen. Diese Scripte laufen und führen Dienste aus, bis zum restlosen_ timeout_. Es geschieht jeweils immer in einer Whileschleife.
1. Schreiben der aktuellen Laufzeit in eine Datei
2. Prüfen ob Datenbankverbindung steht, wenn nein Aufbauen, wenn scheitert sleep() und Ende. (exit
3. Prüfen ob ein Dienst durchgeführt werden muss. Wenn ja Dienst ausführen.
4. Sleep() per Intervall.

Dann gibt es ein Mainscript. Dieses Script prüft nur, ob die Aufgaben gemäß der Zeitstempel in den Textdateien ausgeführt wurden. Es kann praktisch dies nur danach erkennen. Ist dies nicht der Fall, wird dieser Cron diese Rutine (Aufgabe) starten. Dazu weiß das Cron wie lange ein Dienst sich maximal nicht in die Textdatei schreiben darf. Danach ist das Script abgelaufen, und wird wieder nach einer Minute per Intervall gestartet. So kann man PHP zu einen Programm problemlos machen. Wenn auch ein echtes Programm viel sinvoller ist.

Es belastet den Rechner so gut wie garnicht. Die Prozesse die den Interpreter belasten, brauchen ein paar KB je nach Aufgabe. Ich kann das also super empfehelen. Ist praktisch eine billig Lösung für ein interpretierendes Programm.

Aber nun gibt es ein kleines Problem für mich. Welches ich über diese Methode zwar lösen kann, aber eben nicht Datenbankschonend. Und genau deshalb muss ich mich damit noch an eine Systemvariable o. ä. docken. Dann könnte ich diese Zeit praktisch zwischenspeichern, und liefer diese bei Abfrage von aussen nur noch aus. Die Grundlage ist also da. Mein PHP Montrum würde einmal alle 30 Sekunden die Zeit abfragen und irgendwo hinterlegen. (timestamp) etc. Während eine CGI nur noch das System frägt und ausgeliefert. Und nur diese Mauer brauche ich nur noch durchbrechen.


----------

