Ich arbeite an einer etwas großen Webanwendung und das Backend ist meistens in PHP. Es gibt mehrere Stellen im Code, an denen ich eine Aufgabe ausführen muss, aber ich möchte den Benutzer nicht auf das Ergebnis warten lassen. Wenn ich beispielsweise ein neues Konto erstelle, muss ich ihnen eine Willkommens-E-Mail senden. Wenn sie jedoch auf die Schaltfläche "Registrierung beenden" klicken, möchte ich sie nicht warten lassen, bis die E-Mail tatsächlich gesendet wird. Ich möchte nur den Vorgang starten und sofort eine Nachricht an den Benutzer zurücksenden.
Bis jetzt habe ich an einigen Stellen etwas verwendet, das sich wie ein Hack mit exec () anfühlt. Grundsätzlich Dinge tun wie:
exec("doTask.php $arg1 $arg2 $arg3 >/dev/null 2>&1 &");
Was zu funktionieren scheint, aber ich frage mich, ob es einen besseren Weg gibt. Ich denke darüber nach, ein System zu schreiben, das Aufgaben in einer MySQL-Tabelle in die Warteschlange stellt, und ein separates PHP-Skript mit langer Laufzeit, das diese Tabelle einmal pro Sekunde abfragt und alle neu gefundenen Aufgaben ausführt. Dies hätte auch den Vorteil, dass ich die Aufgaben in Zukunft auf mehrere Arbeitsmaschinen aufteilen könnte, wenn dies erforderlich wäre.
Erfinde ich das Rad neu? Gibt es eine bessere Lösung als den exec () - Hack oder die MySQL-Warteschlange?
quelle
Wenn Sie nur eine oder mehrere HTTP-Anforderungen ausführen möchten, ohne auf die Antwort warten zu müssen, gibt es auch eine einfache PHP-Lösung.
Im aufrufenden Skript:
In der aufgerufenen script.php können Sie diese PHP-Funktionen in den ersten Zeilen aufrufen:
Dies führt dazu, dass das Skript ohne zeitliche Begrenzung weiter ausgeführt wird, wenn die HTTP-Verbindung geschlossen wird.
quelle
Eine andere Möglichkeit, Prozesse zu gabeln, ist das Einrollen. Sie können Ihre internen Aufgaben als Webservice einrichten. Beispielsweise:
Rufen Sie dann in den Skripten Ihres Benutzers den Dienst auf:
Ihr Dienst kann die Warteschlange der Aufgaben mit MySQL verfolgen oder was auch immer Sie möchten: Es ist alles im Dienst zusammengefasst und Ihr Skript verbraucht nur URLs. Auf diese Weise können Sie den Dienst bei Bedarf auf einen anderen Computer / Server verschieben (dh leicht skalierbar).
Durch Hinzufügen einer http-Autorisierung oder eines benutzerdefinierten Autorisierungsschemas (wie bei den Webdiensten von Amazon) können Sie Ihre Aufgaben für andere Personen / Dienste öffnen (falls gewünscht), und Sie können noch weiter gehen und einen Überwachungsdienst hinzufügen, um den Überblick zu behalten Warteschlangen- und Aufgabenstatus.
Es erfordert ein wenig Einrichtungsarbeit, aber es gibt viele Vorteile.
quelle
Ich habe Beanstalkd benutzt für ein Projekt verwendet und habe es wieder geplant. Ich habe festgestellt, dass dies eine hervorragende Möglichkeit ist, asynchrone Prozesse auszuführen.
Ein paar Dinge, die ich damit gemacht habe, sind:
Ich habe ein Zend-Framework-basiertes System geschrieben, um eine 'nette' URL zu dekodieren, um beispielsweise die Größe eines aufgerufenen Bildes zu ändern
QueueTask('/image/resize/filename/example.jpg')
. Die URL wurde zuerst in ein Array (Modul, Controller, Aktion, Parameter) dekodiert und dann zur Injektion in die Warteschlange selbst in JSON konvertiert.Ein lang laufendes CLI-Skript nahm dann den Job aus der Warteschlange auf, führte ihn aus (über Zend_Router_Simple) und legte bei Bedarf Informationen in memcached ab, damit das Website-PHP sie nach Bedarf abrufen kann.
Eine Falte, die ich auch hinzugefügt habe, war, dass das Cli-Skript vor dem Neustart nur 50 Schleifen lang lief, aber wenn es wie geplant neu gestartet werden wollte, würde es dies sofort tun (über ein Bash-Skript ausgeführt). Wenn es ein Problem gab und ich es tat
exit(0)
(der Standardwert fürexit;
oderdie();
), wurde es zuerst für ein paar Sekunden angehalten.quelle
Wenn es nur um die Bereitstellung teurer Aufgaben geht und PHP-Fpm unterstützt wird, warum nicht die
fastcgi_finish_request()
Funktion verwenden?Sie verwenden Asynchronität nicht wirklich auf folgende Weise:
fastcgi_finish_request()
.Wieder wird php-fpm benötigt.
quelle
Hier ist eine einfache Klasse, die ich für meine Webanwendung codiert habe. Es ermöglicht das Verzweigen von PHP-Skripten und anderen Skripten. Funktioniert unter UNIX und Windows.
quelle
Dies ist die gleiche Methode, die ich seit ein paar Jahren verwende und die ich nicht besser gesehen oder gefunden habe. Wie die Leute gesagt haben, ist PHP Single-Threaded, so dass Sie nicht viel anderes tun können.
Ich habe dem tatsächlich eine zusätzliche Ebene hinzugefügt, die die Prozess-ID abruft und speichert. Auf diese Weise kann ich auf eine andere Seite umleiten und den Benutzer auf dieser Seite sitzen lassen. Mit AJAX kann ich überprüfen, ob der Prozess abgeschlossen ist (Prozess-ID existiert nicht mehr). Dies ist nützlich in Fällen, in denen die Länge des Skripts zu einer Zeitüberschreitung des Browsers führen würde, der Benutzer jedoch vor dem nächsten Schritt warten muss, bis das Skript abgeschlossen ist. (In meinem Fall wurden große ZIP-Dateien mit CSV-ähnlichen Dateien verarbeitet, die der Datenbank bis zu 30.000 Datensätze hinzufügen. Danach muss der Benutzer einige Informationen bestätigen.)
Ich habe auch einen ähnlichen Prozess für die Berichterstellung verwendet. Ich bin mir nicht sicher, ob ich "Hintergrundverarbeitung" für etwas wie eine E-Mail verwenden würde, es sei denn, es gibt ein echtes Problem mit einem langsamen SMTP. Stattdessen könnte ich eine Tabelle als Warteschlange verwenden und dann einen Prozess ausführen, der jede Minute ausgeführt wird, um die E-Mails in der Warteschlange zu senden. Sie müssen vorsichtig sein, E-Mails zweimal oder ähnliche Probleme zu senden. Ich würde einen ähnlichen Warteschlangenprozess auch für andere Aufgaben in Betracht ziehen.
quelle
PHP HAT Multithreading, es ist nur standardmäßig nicht aktiviert. Es gibt eine Erweiterung namens pthreads, die genau das tut. Sie benötigen jedoch PHP, das mit ZTS kompiliert wurde. (Thread Safe) Links:
Beispiele
Ein weiteres Tutorial
pthreads PECL-Erweiterung
quelle
Es ist eine großartige Idee, cURL zu verwenden, wie von Rojoca vorgeschlagen.
Hier ist ein Beispiel. Sie können text.txt überwachen, während das Skript im Hintergrund ausgeführt wird:
quelle
Leider verfügt PHP über keine nativen Threading-Funktionen. Ich denke, in diesem Fall haben Sie keine andere Wahl, als einen benutzerdefinierten Code zu verwenden, um das zu tun, was Sie tun möchten.
Wenn Sie im Internet nach PHP-Threading suchen, haben sich einige Leute Möglichkeiten ausgedacht, um Threads in PHP zu simulieren.
quelle
Wenn Sie den HTTP-Header für die Inhaltslänge in Ihrer Antwort "Vielen Dank für die Registrierung" festlegen, sollte der Browser die Verbindung schließen, nachdem die angegebene Anzahl von Bytes empfangen wurde. Dadurch wird der serverseitige Prozess ausgeführt (vorausgesetzt, ignore_user_abort ist festgelegt), sodass die Arbeit beendet werden kann, ohne dass der Endbenutzer warten muss.
Natürlich müssen Sie die Größe Ihres Antwortinhalts berechnen, bevor Sie die Header rendern, aber das ist für kurze Antworten ziemlich einfach (Ausgabe in eine Zeichenfolge schreiben, strlen () aufrufen, header () aufrufen, Zeichenfolge rendern).
Dieser Ansatz hat den Vorteil , dass Sie nicht gezwungen werden, eine "Front-End" -Warteschlange zu verwalten. Auch wenn Sie möglicherweise einige Arbeiten am Back-End ausführen müssen, um zu verhindern, dass untergeordnete HTTP-Prozesse aufeinander treffen, müssen Sie dies bereits tun , wie auch immer.
quelle
header('Content-Length: 3'); echo '1234'; sleep(5);
dann benutze , obwohl der Browser nur 3 Zeichen benötigt, wartet er immer noch 5 Sekunden, bevor die Antwort angezeigt wird. Was vermisse ich?phpinfo()
. Das einzige andere, was ich mir vorstellen kann, ist, dass ich zuerst eine minimale Puffergröße erreichen muss, z. B. 256 Byte oder so.Wenn Sie nicht den vollständigen ActiveMQ möchten, empfehle ich, RabbitMQ in Betracht zu ziehen . RabbitMQ ist ein leichtes Messaging, das den AMQP-Standard verwendet .
Ich empfehle auch php-amqplib - eine beliebte AMQP -Clientbibliothek für den Zugriff auf AMQP-basierte Nachrichtenbroker.
quelle
Ich denke, Sie sollten diese Technik ausprobieren. Es wird helfen, so viele Seiten aufzurufen, wie Sie möchten. Alle Seiten werden unabhängig voneinander gleichzeitig ausgeführt, ohne auf jede Seitenantwort als asynchron zu warten.
cornjobpage.php // Hauptseite
testpage.php
PS: Wenn Sie URL-Parameter als Schleife senden möchten, folgen Sie dieser Antwort: https://stackoverflow.com/a/41225209/6295712
quelle
Das Laichen neuer Prozesse auf dem Server mithilfe
exec()
von Curl oder direkt auf einem anderen Server mithilfe von Curl ist überhaupt nicht gut skalierbar. Wenn wir uns für Exec entscheiden, füllen Sie Ihren Server im Grunde genommen mit lang laufenden Prozessen, die von anderen Servern ohne Webkontakt verarbeitet werden können. Durch die Verwendung von Curl wird ein anderer Server gebunden, es sei denn, Sie bauen eine Art Lastausgleich ein.Ich habe Gearman in einigen Situationen verwendet und finde es besser für diese Art von Anwendungsfall. Ich kann einen einzelnen Jobwarteschlangenserver verwenden, um im Grunde die Warteschlange aller Jobs zu verwalten, die vom Server ausgeführt werden müssen, und Arbeitsserver zu starten, von denen jeder so viele Instanzen des Arbeitsprozesses ausführen kann, wie erforderlich, und die Anzahl der zu erhöhen Worker-Server nach Bedarf und drehen Sie sie herunter, wenn sie nicht benötigt werden. Außerdem kann ich die Worker-Prozesse bei Bedarf vollständig herunterfahren und die Jobs in die Warteschlange stellen, bis die Worker wieder online sind.
quelle
PHP ist eine Single-Threaded-Sprache, daher gibt es keine offizielle Möglichkeit, einen asynchronen Prozess damit zu starten, außer
exec
oderpopen
. Es gibt eine Blog - Post über das hier . Ihre Idee für eine Warteschlange in MySQL ist ebenfalls eine gute Idee.Ihre spezielle Anforderung besteht darin, eine E-Mail an den Benutzer zu senden. Ich bin gespannt, warum Sie dies asynchron versuchen, da das Senden einer E-Mail eine ziemlich triviale und schnelle Aufgabe ist. Ich nehme an, wenn Sie Tonnen von E-Mails senden und Ihr ISP Sie wegen des Verdachts auf Spam blockiert, könnte dies ein Grund für eine Warteschlange sein, aber ansonsten kann ich mir keinen Grund vorstellen, dies auf diese Weise zu tun.
quelle