mezzio / mezzio-swoole

Swoole support for Mezzio
https://docs.mezzio.dev/mezzio-swoole/
BSD 3-Clause "New" or "Revised" License
89 stars 28 forks source link

App specific listeners for swoole events #1

Closed weierophinney closed 3 years ago

weierophinney commented 4 years ago

Use swoole tick timer on the worker process to be able to use it as the event loop for guzzle.

PS: By default guzzle uses PHP shutdown handler but this does not work in a swoole environment. To be able to use async Guzzle callbacks within an swoole worker you have to run the task queue of Guzzle manually. This can simply be done using the SwooleServer::tick function of the worker process.

Code to reproduce the issue

// This does not work as "SwooleServer::on()" supports only one listener
// and there is already a listener in SwooleRequestHandlerRunner
$masterServer = $container->get(SwooleHttpServer::class);
$masterServer->on('workerstart', function (SwooleHttpServer $workerServer) {
    $queue = \GuzzleHttp\Promise\queue();
    $workerServer->tick(100, function () use ($queue) {
        $queue->run();
    });
});

// I had to extend SwooleRequestHandlerRunner
// and copy-past SwooleRequestHandlerRunnerFactory
// to use an own event manager to add application specific listeners to these events
$em = $container->get(EventManagerInterface::class);
$em->attach(WorkerStartEvent::class, function (WorkerStartEvent $event) {
    $queue = \GuzzleHttp\Promise\queue();
    $workerServer = $event->getServer();
    $workerServer->tick(1000, function () use ($queue) {
        $queue->run();
    });
});

Expected results

There should already be a way in zend-expressive-swoole to add application specific listeners to such events

Actual results

It's not possible without extending SwooleRequestHandlerRunner and copy-pasting SwooleRequestHandlerRunnerFactory.


Originally posted by @marc-mabe at https://github.com/zendframework/zend-expressive-swoole/issues/69

weierophinney commented 4 years ago

I think the way to make this work is to have the various Swoole event listeners we register trigger their own events via a PSR-14 event dispatcher. This way, we can allow for scenarios like this.

Essentially, in SwooleRequestHandlerRunner, for listeners such as public function onWorkerStart(), they would read:

public function onWorkerStart(SwooleHttpServer $server, int $workerId): void
{
    $this->dispatcher->dispatch(new OnWorkerStartEvent($server, $workerId));
}

We would then have a mechanism for adding listeners, and move the logic we currently have into those listeners.

marc-mabe commented 4 years ago

@weierophinney this would be an awesome solution.

eranoitulover commented 4 years ago

@weierophinney It's the code will be like that?