Hi,

vermutlich haben einige von euch schon verschiedene Lösungsansätze für asynchrone Jobs gebraucht/benutzt/darüber gehört. Ich war neulich auch an einem solchen Punkt und habe mir für dessen Lösung PHPResque ausgesucht. PHPResque ist ein auf Resque (Python-Programm) basiertes Framework um Jobs in den Hintergrund auszulagern. Dafür wird einem Job eine Queue (die den Job-Typ identifiziert und die zum Beispiel zur Priorisierung benutzt werden kann), eine Klasse und Parameter übergeben. Die Klasse, die man angibt wird dann von der Hintergrund-Job-Verwaltung initialisiert, die Parameter werden durch ein dynamisch generiertes Feld "args" gesetzt und die Methode "perform" wird ausgeführt.

Nun ist es aber so, dass die Jobs häufig viele der Abhängigkeiten der gesamten Applikation teilen. Dadurch ist es schwer zu entscheiden wie man einen solchen Job definiert (welche Klasse, etc). Ich habe dazu einen Lösungsansatz, der leider nicht ganzen meinen Bedürfnissen entspricht:
Ich habe eine Datei resque.php in den Ordner public gesteckt (vermutlich wäre sie woanders besser aufgehoben), die etwa so aussieht:
PHP-Code:
chdir(dirname(__DIR__));
require 
'init_autoloader.php';
/**
 * Class Application
 * @property mixed args 
 */
class Application {
        public function 
perform() {
                global 
$argc,$argv;
                
$argv explode(' ',$this->args['command']);
                
array_unshift($argv,'resque.php');
                
$argc count($argv)+1;
                
$_SERVER['argv'] = $argv;
                
$_SERVER['argc'] = $argc;
                
$application = \Zend\Mvc\Application::init(require 'config/application.config.php');
                
$application->bootstrap();
                
$application->run();
        }

Sie orientiert sich im Aufbau an der index.php der Skeleton-Application des ZF2.
Um jetzt einen Job für den Hintergrund vorzubereiten führe ich folgenden Befehl aus:
PHP-Code:
Resque::enqueue($queueName"Application", array('command' => $consoleCommand)); 
Die so ausgeführten Befehle müssen über eine console-route erreichbar sein.

So viel zu der bisherigen (funktionierenden) Lösung. Jetzt mein Problem:
Da ich sehr viele sehr kleine Jobs habe, kommt es zu einem deutlichen Overhead durch den Initialisierungs-Prozess. Hierfür hatte ich die Hoffnung wenigstens einen der Befehle
PHP-Code:
$application = \Zend\Mvc\Application::init(require 'config/application.config.php');
$application->bootstrap(); 
schon vor dem fork des PHPResque-Managers auszuführen. Es scheint aber so, als ob der Router die Parameter argv (und evtl. argc, dürfte aber nicht so wichtig sein) schon während dem init ausführen würde. Dadurch kann die Application erst initialisiert werden, wenn man die Parameter kennt, muss also auch für jeden Job einzeln gemacht werden. Das ist unschön. Natürlich gibt es noch andere Möglichkeiten die Initialisierung der Application generell zu beschleunigen, aber vielleicht kennt ja jemand eine naheliegende Lösung um das beschriebene Verhalten zu erreichen.

Generell bin ich auch für Lösungen der grundsätzlichen Problemstellung "asynchrone Jobs ohne auf das Framework zu verzichten" offen.

Viele Grüße

Nick