Führen Sie die PHP-Aufgabe asynchron aus

144

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?

davr
quelle

Antworten:

80

Ich habe den Warteschlangenansatz verwendet, und er funktioniert gut, da Sie diese Verarbeitung verschieben können, bis Ihre Serverlast im Leerlauf ist. So können Sie Ihre Last recht effektiv verwalten, wenn Sie "Aufgaben, die nicht dringend sind" leicht aufteilen können.

Das Rollen Ihrer eigenen ist nicht allzu schwierig. Hier sind einige andere Optionen, die Sie ausprobieren sollten:

  • GearMan - Diese Antwort wurde 2009 geschrieben und seitdem scheint GearMan eine beliebte Option zu sein, siehe Kommentare unten.
  • ActiveMQ, wenn Sie eine vollständige Open Source-Nachrichtenwarteschlange wünschen.
  • ZeroMQ - Dies ist eine ziemlich coole Socket-Bibliothek, die es einfach macht, verteilten Code zu schreiben, ohne sich über die Socket-Programmierung selbst Gedanken machen zu müssen. Sie können es für die Nachrichtenwarteschlange auf einem einzelnen Host verwenden. Ihre Webanwendung muss lediglich etwas in eine Warteschlange verschieben, das eine kontinuierlich ausgeführte Konsolen-App bei der nächsten geeigneten Gelegenheit verbraucht
  • beanstalkd - habe diesen nur beim Schreiben dieser Antwort gefunden, sieht aber interessant aus
  • dropr ist ein PHP-basiertes Nachrichtenwarteschlangenprojekt, das jedoch seit September 2010 nicht mehr aktiv gepflegt wurde
  • php-enqueue ist ein kürzlich (2017) gewarteter Wrapper für eine Vielzahl von Warteschlangensystemen
  • Schließlich ein Blog-Beitrag über die Verwendung von memcached für die Nachrichtenwarteschlange

Ein anderer, vielleicht einfacherer Ansatz ist die Verwendung von ignore_user_abort. Sobald Sie die Seite an den Benutzer gesendet haben, können Sie Ihre endgültige Verarbeitung ohne Angst vor vorzeitiger Beendigung durchführen. Dies hat jedoch den Effekt, dass die Seitenlast des Benutzers verlängert wird Perspektive.

Paul Dixon
quelle
Danke für alle Tipps. Das spezifische über ignore_user_abort hilft in meinem Fall nicht wirklich, mein ganzes Ziel ist es, unnötige Verzögerungen für den Benutzer zu vermeiden.
Davr
2
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), ohne dass der Endbenutzer warten muss. Natürlich müssen Sie vor dem Rendern der Header die Größe Ihres Antwortinhalts berechnen, aber das ist für kurze Antworten ziemlich einfach.
Peter
1
Gearman ( gearman.org ) ist eine großartige Open-Source-Nachrichtenwarteschlange, die plattformübergreifend ist. Sie können Mitarbeiter in C, PHP, Perl oder einer beliebigen anderen Sprache schreiben. Es gibt Gearman UDF-Plugins für MySQL und Sie können auch Net_Gearman von PHP oder dem Gearman Pear Client verwenden.
Justin Swanhart
Gearman wäre das, was ich heute (2015) gegenüber jedem benutzerdefinierten Warteschlangensystem empfehlen würde.
Peter
Eine andere Möglichkeit besteht darin, einen Knoten-js-Server so einzurichten, dass er eine Anforderung verarbeitet und eine schnelle Antwort mit einer dazwischen liegenden Aufgabe zurückgibt. Viele Dinge in einem Knoten-JS-Skript werden asynchron ausgeführt, z. B. eine http-Anforderung.
Zordon
22

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:

$socketcon = fsockopen($host, 80, $errno, $errstr, 10);
if($socketcon) {   
   $socketdata = "GET $remote_house/script.php?parameters=... HTTP 1.1\r\nHost: $host\r\nConnection: Close\r\n\r\n";      
   fwrite($socketcon, $socketdata); 
   fclose($socketcon);
}
// repeat this with different parameters as often as you like

In der aufgerufenen script.php können Sie diese PHP-Funktionen in den ersten Zeilen aufrufen:

ignore_user_abort(true);
set_time_limit(0);

Dies führt dazu, dass das Skript ohne zeitliche Begrenzung weiter ausgeführt wird, wenn die HTTP-Verbindung geschlossen wird.

Markus
quelle
set_time_limit hat keine Auswirkung, wenn PHP im abgesicherten Modus ausgeführt wird
Baptiste Pernet
17

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:

$service->addTask('t1', $data); // post data to URL via curl

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.

Rojoca
quelle
1
Ich mag diesen Ansatz nicht, weil er den Webserver überlastet
Oved Yavine
7

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:

  • Bildgrößenänderung - und mit einer leicht geladenen Warteschlange, die an ein CLI-basiertes PHP-Skript übergeben wird, funktionierte die Größenänderung großer (2 MB +) Bilder einwandfrei, aber der Versuch, die Größe derselben Bilder in einer mod_php-Instanz zu ändern, führte regelmäßig zu Speicherplatzproblemen (I. beschränkte den PHP-Prozess auf 32 MB, und die Größenänderung dauerte mehr als das)
  • Überprüfungen in naher Zukunft - Beanstalkd verfügt über Verzögerungen (stellen Sie diesen Job erst nach X Sekunden zur Ausführung bereit) - damit ich etwas später 5 oder 10 Überprüfungen für ein Ereignis auslösen kann

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ür exit;oder die();), wurde es zuerst für ein paar Sekunden angehalten.

Alister Bulman
quelle
Ich mag das Aussehen von Bohnenstange, wenn sie einmal Ausdauer haben, denke ich, dass es perfekt sein wird.
Davr
Das ist schon in der Codebasis und wird stabilisiert. Ich freue mich auch auf "benannte Jobs", damit ich Dinge hineinwerfen kann, aber ich weiß, dass sie nicht hinzugefügt werden, wenn es bereits einen gibt. Gut für regelmäßige Veranstaltungen.
Alister Bulman
@AlisterBulman könnten Sie weitere Informationen oder Beispiele für "Ein lang laufendes CLI-Skript hat dann den Job aus der Warteschlange aufgenommen" geben. Ich versuche, ein solches CLI-Skript für meine Anwendung zu erstellen.
Sasi Varna Kumar
7

Wenn es nur um die Bereitstellung teurer Aufgaben geht und PHP-Fpm unterstützt wird, warum nicht die fastcgi_finish_request()Funktion verwenden?

Diese Funktion löscht alle Antwortdaten an den Client und beendet die Anforderung. Auf diese Weise können zeitaufwändige Aufgaben ausgeführt werden, ohne dass die Verbindung zum Client offen bleibt.

Sie verwenden Asynchronität nicht wirklich auf folgende Weise:

  1. Machen Sie zuerst Ihren gesamten Hauptcode.
  2. Ausführen fastcgi_finish_request().
  3. Mach alles schwere Zeug.

Wieder wird php-fpm benötigt.

Denys Gorobchenko
quelle
5

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.

class BackgroundProcess {
    static function open($exec, $cwd = null) {
        if (!is_string($cwd)) {
            $cwd = @getcwd();
        }

        @chdir($cwd);

        if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
            $WshShell = new COM("WScript.Shell");
            $WshShell->CurrentDirectory = str_replace('/', '\\', $cwd);
            $WshShell->Run($exec, 0, false);
        } else {
            exec($exec . " > /dev/null 2>&1 &");
        }
    }

    static function fork($phpScript, $phpExec = null) {
        $cwd = dirname($phpScript);

        @putenv("PHP_FORCECLI=true");

        if (!is_string($phpExec) || !file_exists($phpExec)) {
            if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
                $phpExec = str_replace('/', '\\', dirname(ini_get('extension_dir'))) . '\php.exe';

                if (@file_exists($phpExec)) {
                    BackgroundProcess::open(escapeshellarg($phpExec) . " " . escapeshellarg($phpScript), $cwd);
                }
            } else {
                $phpExec = exec("which php-cli");

                if ($phpExec[0] != '/') {
                    $phpExec = exec("which php");
                }

                if ($phpExec[0] == '/') {
                    BackgroundProcess::open(escapeshellarg($phpExec) . " " . escapeshellarg($phpScript), $cwd);
                }
            }
        } else {
            if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
                $phpExec = str_replace('/', '\\', $phpExec);
            }

            BackgroundProcess::open(escapeshellarg($phpExec) . " " . escapeshellarg($phpScript), $cwd);
        }
    }
}
Andrew Moore
quelle
4

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.

Darryl Hein
quelle
1
Auf welche Methode beziehen Sie sich in Ihrem ersten Satz?
Simon East
3

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

Omar S.
quelle
2

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:

<?php

function doCurl($begin)
{
    echo "Do curl<br />\n";
    $url = 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
    $url = preg_replace('/\?.*/', '', $url);
    $url .= '?begin='.$begin;
    echo 'URL: '.$url.'<br>';
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    echo 'Result: '.$result.'<br>';
    curl_close($ch);
}


if (empty($_GET['begin'])) {
    doCurl(1);
}
else {
    while (ob_get_level())
        ob_end_clean();
    header('Connection: close');
    ignore_user_abort();
    ob_start();
    echo 'Connection Closed';
    $size = ob_get_length();
    header("Content-Length: $size");
    ob_end_flush();
    flush();

    $begin = $_GET['begin'];
    $fp = fopen("text.txt", "w");
    fprintf($fp, "begin: %d\n", $begin);
    for ($i = 0; $i < 15; $i++) {
        sleep(1);
        fprintf($fp, "i: %d\n", $i);
    }
    fclose($fp);
    if ($begin < 10)
        doCurl($begin + 1);
}

?>
Kjeld
quelle
2
Es wäre wirklich hilfreich, wenn der Quellcode kommentiert würde. Ich habe keine Ahnung, was dort vor sich geht und welche Teile beispielhaft sind und welche Teile für meinen eigenen Zweck wiederverwendbar sind.
Thomas Tempelmann
1

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.

Peter D.
quelle
1

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.

Peter
quelle
Das scheint nicht zu funktionieren. Wenn ich 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?
Thomas Tempelmann
@ThomasTempelmann - Sie müssen wahrscheinlich flush () aufrufen, um zu erzwingen, dass die Ausgabe sofort gerendert wird. Andernfalls wird die Ausgabe gepuffert, bis Ihr Skript beendet wird oder genügend Daten an STDOUT gesendet werden, um den Puffer zu leeren.
Peter
Ich habe bereits viele Möglichkeiten zum Spülen ausprobiert, die hier auf SO zu finden sind. Keine Hilfe. Und die Daten scheinen auch nicht gezippt gesendet zu werden, wie man sehen kann 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.
Thomas Tempelmann
@ThomasTempelmann - Ich sehe nichts in Ihrer Frage oder meiner Antwort zu gzip (normalerweise ist es sinnvoll, das einfachste Szenario zuerst zum Laufen zu bringen, bevor Sie Komplexitätsebenen hinzufügen). Um festzustellen, wann der Server tatsächlich Daten sendet, können Sie einen Paket-Sniffer des Browser-Plugins (wie Fiddler, Tamperdata usw.) verwenden. Wenn Sie dann feststellen, dass der Webserver wirklich alle Skriptausgaben bis zum Beenden hält, unabhängig vom Leeren, müssen Sie Ihre Webserverkonfiguration ändern (in diesem Fall kann Ihr PHP-Skript nichts tun).
Peter
Ich verwende einen virtuellen Webdienst, daher habe ich wenig Kontrolle über dessen Konfiguration. Ich hatte gehofft, andere Vorschläge zu finden, was der Schuldige sein könnte, aber es scheint, dass Ihre Antwort einfach nicht so universell anwendbar ist, wie es scheint. Offensichtlich können zu viele Dinge schief gehen. Ihre Lösung ist sicherlich viel einfacher zu implementieren als alle anderen hier angegebenen Antworten. Schade, dass es bei mir nicht funktioniert.
Thomas Tempelmann
1

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.

phpPhil
quelle
0

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

    <?php

post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue");
//post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue2");
//post_async("http://localhost/projectname/otherpage.php", "Keywordname=anyValue");
//call as many as pages you like all pages will run at once independently without waiting for each page response as asynchronous.
            ?>
            <?php

            /*
             * Executes a PHP page asynchronously so the current page does not have to wait for it to     finish running.
             *  
             */
            function post_async($url,$params)
            {

                $post_string = $params;

                $parts=parse_url($url);

                $fp = fsockopen($parts['host'],
                    isset($parts['port'])?$parts['port']:80,
                    $errno, $errstr, 30);

                $out = "GET ".$parts['path']."?$post_string"." HTTP/1.1\r\n";//you can use POST instead of GET if you like
                $out.= "Host: ".$parts['host']."\r\n";
                $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
                $out.= "Content-Length: ".strlen($post_string)."\r\n";
                $out.= "Connection: Close\r\n\r\n";
                fwrite($fp, $out);
                fclose($fp);
            }
            ?>

testpage.php

    <?
    echo $_REQUEST["Keywordname"];//case1 Output > testValue
    ?>

PS: Wenn Sie URL-Parameter als Schleife senden möchten, folgen Sie dieser Antwort: https://stackoverflow.com/a/41225209/6295712

Hassan Saeed
quelle
0

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.

Chris Rutherfurd
quelle
-4

PHP ist eine Single-Threaded-Sprache, daher gibt es keine offizielle Möglichkeit, einen asynchronen Prozess damit zu starten, außer execoder popen. 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.

Marc W.
quelle
Die E-Mail war nur ein Beispiel, da die anderen Aufgaben komplexer zu erklären sind und es nicht wirklich um die Frage geht. So wie wir E-Mails gesendet haben, wurde der E-Mail-Befehl erst zurückgegeben, wenn der Remote-Server die E-Mail akzeptiert hat. Wir haben festgestellt, dass einige Mailserver so konfiguriert wurden, dass lange Verzögerungen (z. B. Verzögerungen von 10 bis 20 Sekunden) hinzugefügt werden, bevor E-Mails angenommen werden (wahrscheinlich um Spambots zu bekämpfen). Diese Verzögerungen werden dann an unsere Benutzer weitergegeben. Jetzt verwenden wir einen lokalen Mailserver, um die zu sendenden Mails in die Warteschlange zu stellen. Dieser gilt also nicht, aber wir haben andere Aufgaben ähnlicher Art.
Davr
Beispiel: Das Senden von E-Mails über Google Apps Smtp mit SSL und Port 465 dauert länger als gewöhnlich.
Gixty