mezzio / mezzio-swoole

Swoole support for Mezzio

Home Page:https://docs.mezzio.dev/mezzio-swoole/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Provide a way to operate over original swoole server instance

arku31 opened this issue · comments

I would be happy to see protected const in that class as by extending the class with private const I am forced to define it in my own and they are not different to the default one.

private const MODES = [

I am extending it to perform some code before the swoole server starts

Can you indicate how you would be using this in your own code, exactly?

I only defined that particular constant so that we could internally ensure that the mode provided via configuration is valid, which is something that can be done easily in userland already (e.g., in_array($mode, [SWOOLE_PROCESS, SWOOLE_BASE], true).

I would like to perform some actions with the original server instance. (in particular, inject https://github.com/upscalesoftware/swoole-newrelic).

In order to achieve this, I am extending HttpServerFactory and do

    public function __invoke(ContainerInterface $container): SwooleHttpServer
{
   $server = parent::__invoke($container);
   //somestuff with $server;
   return $server;
}

Unfortunately, it doesn't work out because of private constants, they are not available in the child class and it leads to errors :(

P.S. There are several more issues like that, I will create another issue if we would agree on this one :)

Where are you injecting? I assume potentially an event listener? If you're using mezzio-swoole v3, you likely will want to do this via our new event system, which ties into all the workflow events of the Swoole HTTP server, and which you can do without needing to change the factory (see the events and listeners documentation).

Alternately, if you are trying to add config settings or otherwise manipulate the instance, potentially try using delegator factories.

Unfortunately, this cannot be bootstrapped after the server has been started :(
I am not sure that I understood it correctly but seems like delegator factories is also a wrong way for me.

In the end, to achieve my goals, I only was able to put the code in the SwooleRequestHandlerRunner

Between
...$this->httpServer->on('request', [$this, 'onTaskFinish']);...
and
$this->httpServer->start();

The problem is that to use this library, I have to have server not started but ->on('request') callback already defined.

Unfortunately, this class is also not really extendable because of the private properties that force you to duplicate basically everything.

private EventDispatcherInterface $dispatcher;

UPD:
Currently, I can see two options:

  • simple: make private property protected to allow proper code extension
  • better but also a bit harder - provide a way to inject some code between callbacks definition and the actual server start

Please read the documentation - you can add listeners to the various Swoole HTTP Server by instead adding listeners to the event classes found under Mezzio\Swoole\Event. The request handler runner has listeners that dispatch those events, which allows users to attach multiple listeners to them — which is something the Swoole HTTP server does not allow natively.

In this case, if you want it to run via the Swoole HTTP Server 'request' event, and want your listener to trigger first, you'd add configuration like this:

use Laminas\Stdlib\ArrayUtils\MergeReplaceKey;
use Mezzio\Swoole\Event;

return [
    'mezzio-swoole' => [
        'swoole-http-server' => [
            'listeners' => [
                Event\RequestEvent:class => new MergeReplaceKey([
                    YourListenerGoesHere::class, // you can also do a class instance here, but your config will no longer be cacheable
                    Event\StaticResourceRequestListener::class,
                    Event\RequestHandlerRequestListener::class,
                ]),
            ],
        ],
    ],
];

Basically, you should NEVER attach directly to the Swoole HTTP Server lifecycle events; attach listeners to the internal dispatcher instead, as it allows you to compose multiple listeners safely.

The problem, why I cannot use Event/Listeners is the fact, that I want to measure the time, that request has taken.
There is already a package that can do it by injecting into swoole server (it takes the current callback and injects in between, so it shouldn't affect anything what is defined on the application level). Alternatively, I can imagine, it can be done with two Listeners, like "Before request" and "Response about to being send" but they doesn't exists, we only have onRequest.

I tried to achieve it by having Listener before and after RequestHandlerRequestListener but after the response is being sent, nothing is executed.

so, once again,
I can currently only see an option to extend SwooleRequestHandlerRunner and overwrite run() method what looks more or less good solution for me but I cannot (simply) do it because of private properties. Can we do them protected or agree that it's not extendable (probably make it final)

Thanks!