Delphi-PRAXiS
Seite 1 von 2  1 2   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   PHP: Skript parallel starten (https://www.delphipraxis.net/161407-php-skript-parallel-starten.html)

implementation 2. Jul 2011 08:34

PHP: Skript parallel starten
 
Hallo liebes Stammforum,

angenommen ich habe ein PHP-Skript A, dass vom Client angefordert wird.
Dieses soll jetzt im Hintergrund auf dem Server ein weiteres Skript B starten,
das nur an der Datenbank rumwerkelt.
Also etwa so:

-> A wird ausgeführt
-> A startet B
-> A liefert Ergebnis an Client zurück
-> B läuft im Hintergrund weiter
...
-> C wird ausgeführt
-> C beendet B
-> C liefert XML/JSON an Client zurück

Wie könnte ich das lösen?
Das beenden wäre ja nicht einmal das Problem, C könnte ja einen DB-Eintrag setzen, bei dem B sich selbst beendet.
Aber wie starte ich es?

alcaeus 2. Jul 2011 09:39

AW: PHP: Skript parallel starten
 
Moin,

um asynchrone Jobs zu starten gibt es mehrere Extensions. Ich bevorzuge hier Gearman, aus ganz einfachen Gruenden:
  • Die Client-Libraries, mit denen Jobs gestartet werden, gibt es fuer viele Programmiersprachen
  • Es ist kein Problem, ueber ein PHP-Script einen Job zu starten, der aber in C, Java oder Python geschrieben ist. Du kannst fuer jeden Teil der Anwendung die beste Sprache auswaehlen.
  • Die Datenuebertragung funktioniert anhand von Strings (genauer gesagt ein String-Parameter, ein String-Return), d.h. du entscheidest selbst wie du die Daten uebertragen willst (z.B. JSON-encodiert)
  • Es gibt eine telnet-Konsole, ueber die du den Status des Gearman ueberwachen kannst

Nachteil ist natuerlich, dass du einerseits ein apt-Paket fuer den Gearman-Server installieren musst sowie eine PECL-Extension (gearman) installieren musst damit alles laeuft. Hier ein Kurzueberblick wie das funktioniert.

Dein Script B, welches asynchron im Hintergrund laeuft, wird als Gearman-Skript registriert. Beim Start meldet es sich bei einem Gearman-Server an und registriert eine oder mehrere Funktionen und hinterlegt dazu eine Callback-Funktion, die dann tatsaechlich ausgefuehrt wird. Anschliessend tritt es in einen busy-waiting-Status und wartet auf Jobs.

Dein Script A sieht dass ein Hintegrundskript ausgefuehrt werden muss und baut ebenfalls eine Verbindung zum Gearman-Server auf. Anschliessend teilst du dem Gearman-Server mit, welche Funktion du ausfuehren willst und gibst ihm noch einen String-Parameter dazu. Du kannst auch entscheiden, ob du das Skript synchron oder asynchron starten willst. Bei der synchronen Ausfuehrung erhaelst du als Rueckgabewert das Ergebnis der in Script B ausgefuehrten Funktion (auch hier wieder nur ein String). Bie der asynchronen Ausfuehrung erhaelst du ein Token als Rueckgabewert, mit dem du den Status des Jobs pruefen kannst.

Damit Script C das Ergebnis am Ende irgendwo abholen kann, muss es einerseits das Token wissen, Script B muss das Ergebnis aber auch irgendwohin schreiben. Der Gearman-Server "vergisst" das naemlich, sobald Script B durch ist. Alternativ koenntest du auch mit Gearman-Tasks arbeiten, damit habe ich aber noch nicht viel gemacht.

Angenommen du hast nun die Scripte geschrieben und stellst fest dass die Ausfuehrung von Script B ueber Gearman lang dauert, weil viele Jobs in der Queue sind. Jede Instanz eines Gearman-Worker kann immer nur einen Job abarbeiten. Erst sobald dieser abgearbeitet ist, kommt der naechste dran. Du kannst aber soviele Instanzen starten wie du willst. Dann geschieht die Ausfuehrung von mehreren Tasks parallel.
Nun waechst die Anwendung weiter und du stellst fest dass der Server auf dem die Gearman-Jobs laufen komplett ausgelastet ist. Du kannst auch hier weiterskalieren und einfach auf einem zweiten Server dasselbe Script x-mal starten und wieder beim selben Gearman-Server registrieren. Dann verteilt der Gearman-Server die Jobs auch auf die beiden Maschinen.
Dieser Gearman-Server benoetigt normalerweise nicht viele Resourcen, aber es kann trotzdem sein dass er ueberlastet ist. Du kannst auch mehrere Instanzen eines Gearman-Servers aufsetzen. Wenn sich die Jobs alle bei allen Servern registrieren und die Clients in Script A sich auch bei allen Servern registrieren wird auch der Management-Teil skaliert. Du kannst diese Loesung also komplett in alle Richtungen skalieren, je nachdem wie du es brauchst.

So, ich hoff dass das halbwegs verstaendlich ist. Die PHP-Doku zur Gearman-Extension gibt dir einen guten Ueberblick ueber die Funktionen sowie ein paar Beispiele, anhand denen du das erstmal testen kannst. Auch die Gearman-Seite selbst stellt ein paar PHP-Beispiele zur Verfuegung.

Greetz
alcaeus

implementation 2. Jul 2011 10:15

AW: PHP: Skript parallel starten
 
Hmm, danke für deine ausführliche Antwort.
Leider hab ich auf den Server bloß nichts anderes als einen FTP-Zugang, Datenbank-Zugänge und PHP-Ausführungsrechte. Mit apt ist da nix :stupid:
Ich gehe mal davon aus, dass auf dem Freehoster kein Gearman installiert ist.
Dann sieht es wohl so aus, als müsst ich das anders lösen. Schade.
Aber nochmals Vielen Dank! :thumb:

alcaeus 2. Jul 2011 10:25

AW: PHP: Skript parallel starten
 
Zitat:

Zitat von implementation (Beitrag 1109581)
Leider hab ich auf den Server bloß nichts anderes als einen FTP-Zugang, Datenbank-Zugänge und PHP-Ausführungsrechte. Mit apt ist da nix :stupid:

Du kannst mal gucken ob du die proc_*-Funktionen oder exec() usw. aufrufen kannst. Damit kannst du ebenfalls ein CLI-Script in den Hintergrund schieben. Wenn das nicht geht hast du es richtig schwer.

Greetz
alcaeus

implementation 2. Jul 2011 10:36

AW: PHP: Skript parallel starten
 
Zitat:

Zitat von PHP
exec() has been disabled for security reasons

Wird wohl nix. Dann muss ich mir 'nen Workaround ausdenken, wie ich meinen Wunsch anders lösen kann. :(

alcaeus 2. Jul 2011 11:10

AW: PHP: Skript parallel starten
 
Dann kannst du die absolut haesslichste Variante nehmen, die es nur irgendwie gibt:
Die Seite die den Background-Task starten muss registriert mit register_shutdown_function() eine Funktion, welche ausgefuehrt wird sobald die Ausfuehrung des Scripts beendet wird (weil Ende erreicht oder exit() aufgerufen wurde). Das kostet dich dann zwar einen Apache-Prozess, du hast aber soweit ich weiss noch saemtliche Resourcen wie z.B. DB-Connections usw. Falls die zu dem Zeitpunkt schon weg sind, bleibt dir nichts anderes uebrig als den Output mit flush() rauszuschicken und anschliessend die entsprechende Berechnung oder was auch immer zu machen. Das Ergebnis landet in der DB und das andere Script kann das Ergebnis abholen.

Greetz
alcaeus

blackfin 2. Jul 2011 11:47

AW: PHP: Skript parallel starten
 
Ginge das nicht auch über simples AJAX?
(über jQuery, prototype oder mootools)

A wird aufgerufen, startet via AJAX ein weiteres Script B.
B macht seine Aufgaben, beendet sich aber nicht, da es in eine Schleife geht, die eine php-Session-Variable auf existenz prüft. (warum ist es eigentlich nötig, dass sich B nicht beendet, wenn es fertig ist und das Ergebnis an A per AJAX zurückgibt oder in eine Datei schreibt, so wie es normalerweise der Fall ist?)
C wird aufgerufen, setzt die Session-Variable.
B beendet sich, sobald die Session-Variable von C gesetzt wurde und gibt JSON / XML über Ajax zurück.

Oder habe ich einen Denkfehler? :-)

implementation 2. Jul 2011 12:01

AW: PHP: Skript parallel starten
 
Du hast recht! :shock:
Danke, das dürfte ja tatsächlich gehen :thumb:

Ich wollte sowieso sehr viel Ajax verwenden, da lässt sich das gut einbauen.

Request -> B starten
-> B fügt Datensatz in DB ein
Request -> D holt B's Datensätze und liefert sie zurück
Request -> E fügt Datensätze in DB ein
-> B liest E's Datensätze aus DB
-> B packt neue Datensätze rein
Request -> D holt B's Datensätze und liefert sie zurück
Request -> C setzt Beenden-Befehl in die Datenbank
-> B beendet sich selbst

alcaeus 2. Jul 2011 12:52

AW: PHP: Skript parallel starten
 
Zitat:

Zitat von blackfin (Beitrag 1109591)
B beendet sich, sobald die Session-Variable von C gesetzt wurde und gibt JSON / XML über Ajax zurück.

Da hast du das Problem dass der Browser bis dahin moeglicherweise schon nen Timeout gekriegt hat (z.B. gibt nginx nach 300 Sekunden nen 504 Gateway Timeout zurueck) oder ihn angenommen hat nachdem noch keine Daten gesendet wurden.
Ausserdem, was passiert wenn sich der Status der Applikation aendert, weil z.B. der Benutzer klug genug war, nen Refresh zu machen? Das Ergebnis vom Call an B laeuft dann ins Leere.

Greetz
alcaeus

implementation 2. Jul 2011 13:58

AW: PHP: Skript parallel starten
 
Der AJAX-Request soll ja asynchron sein, der User kriegt also gar nicht mit, dass da im Hintergrund 'nen Skript gestartet wurde. Wieso sollte er dann Refreshen?
Timeouts kann ich ja ignorieren, oder? Es geht mir ja nicht darum, dass B irgendetwas zurückliefert.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:53 Uhr.
Seite 1 von 2  1 2   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz