Test Failed
Pull Request — master (#93)
by
unknown
33:08 queued 19s
created

RoadRunnerGrpcApplicationRunner::getInvoker()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Runner\RoadRunner;
6
7
use Psr\Container\ContainerExceptionInterface;
8
use Psr\Container\ContainerInterface;
9
use Psr\Container\NotFoundExceptionInterface;
10
use Spiral\RoadRunner\GRPC\Invoker;
11
use Spiral\RoadRunner\GRPC\InvokerInterface;
12
use Spiral\RoadRunner\GRPC\Server;
13
use Spiral\RoadRunner\GRPC\ServiceInterface;
14
use Spiral\RoadRunner\Worker;
15
use Yiisoft\Definitions\Exception\InvalidConfigException;
16
use Yiisoft\Di\StateResetter;
17
use Yiisoft\ErrorHandler\ErrorHandler;
0 ignored issues
show
Bug introduced by
The type Yiisoft\ErrorHandler\ErrorHandler was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use Yiisoft\ErrorHandler\Exception\ErrorException;
19
use Yiisoft\ErrorHandler\Renderer\HtmlRenderer;
20
use Yiisoft\Log\Logger;
21
use Yiisoft\Log\Target\File\FileTarget;
22
use Yiisoft\Yii\Runner\ApplicationRunner;
23
24
/**
25
 * `RoadRunnerGrpcApplicationRunner` runs the Yii gRPC application using RoadRunner.
26
 */
27
final class RoadRunnerGrpcApplicationRunner extends ApplicationRunner
28
{
29
    private ?ErrorHandler $temporaryErrorHandler = null;
30
    private ?InvokerInterface $invoker = null;
31
    private array $services = [];
32
    private ?Worker $worker = null;
33
34
    /**
35
     * @param string $rootPath The absolute path to the project root.
36
     * @param bool $debug Whether the debug mode is enabled.
37
     * @param bool $checkEvents Whether to check events' configuration.
38
     * @param string|null $environment The environment name.
39
     * @param string $bootstrapGroup The bootstrap configuration group name.
40
     * @param string $eventsGroup The events' configuration group name.
41
     * @param string $diGroup The container definitions' configuration group name.
42
     * @param string $diProvidersGroup The container providers' configuration group name.
43 2
     * @param string $diDelegatesGroup The container delegates' configuration group name.
44
     * @param string $diTagsGroup The container tags' configuration group name.
45
     * @param string $paramsGroup The configuration parameters group name.
46
     * @param array $nestedParamsGroups Configuration group names that are included into configuration parameters group.
47
     * This is needed for recursive merging of parameters.
48
     * @param array $nestedEventsGroups Configuration group names that are included into events' configuration group.
49
     * This is needed for reverse and recursive merge of events' configurations.
50
     *
51
     * @psalm-param list<string> $nestedParamsGroups
52
     * @psalm-param list<string> $nestedEventsGroups
53
     */
54
    public function __construct(
55
        string $rootPath,
56
        bool $debug = false,
57
        bool $checkEvents = false,
58 2
        ?string $environment = null,
59 2
        string $bootstrapGroup = 'bootstrap-web',
60 2
        string $eventsGroup = 'events-web',
61 2
        string $diGroup = 'di-web',
62 2
        string $diProvidersGroup = 'di-providers-web',
63 2
        string $diDelegatesGroup = 'di-delegates-web',
64 2
        string $diTagsGroup = 'di-tags-web',
65 2
        string $paramsGroup = 'params-web',
66 2
        array $nestedParamsGroups = ['params'],
67 2
        array $nestedEventsGroups = ['events'],
68 2
    ) {
69 2
        parent::__construct(
70 2
            $rootPath,
71 2
            $debug,
72 2
            $checkEvents,
73
            $environment,
74
            $bootstrapGroup,
75 1
            $eventsGroup,
76
            $diGroup,
77 1
            $diProvidersGroup,
78
            $diDelegatesGroup,
79
            $diTagsGroup,
80
            $paramsGroup,
81
            $nestedParamsGroups,
82
            $nestedEventsGroups,
83 1
        );
84 1
    }
85
86
    /**
87 1
     * @return void
88 1
     * @throws ContainerExceptionInterface
89 1
     * @throws ErrorException
90
     * @throws NotFoundExceptionInterface
91
     * @throws \ErrorException
92
     * @throws InvalidConfigException
93
     */
94
    public function run(): void
95
    {
96
        // Register temporary error handler to catch error while container is building.
97 1
        $temporaryErrorHandler = $this->createTemporaryErrorHandler();
98
        $this->registerErrorHandler($temporaryErrorHandler);
99 1
100 1
        $container = $this->getContainer();
101
102 1
        // Register error handler with real container-configured dependencies.
103
        /** @var ErrorHandler $actualErrorHandler */
104
        $actualErrorHandler = $container->get(ErrorHandler::class);
105
        $this->registerErrorHandler($actualErrorHandler, $temporaryErrorHandler);
106
107
        $this->runBootstrap();
108
        $this->checkEvents();
109
110
        $server = new Server($this->getInvoker(), ['debug' => $this->debug]);
111
112
        /**
113
         * @var class-string<ServiceInterface> $interface
114
         */
115
        foreach ($this->getServices() as $interface) {
116
            $server->registerService($interface, $container->get($interface));
117 2
        }
118
119 2
        $server->serve($this->getWorker(), finalize: function () use ($container) {
120
            $this->afterRespond($container);
121 2
        });
122
    }
123
124 2
    private function createTemporaryErrorHandler(): ErrorHandler {
125
        if ($this->temporaryErrorHandler !== null) {
126 2
            return $this->temporaryErrorHandler;
127
        }
128
129 1
        $logger = new Logger([new FileTarget("$this->rootPath/runtime/logs/app.log")]);
130
        return new ErrorHandler($logger, new HtmlRenderer());
131 1
    }
132
133
    /**
134 1
     * @throws ErrorException
135
     */
136 1
    private function registerErrorHandler(ErrorHandler $registered, ErrorHandler $unregistered = null): void {
137
        $unregistered?->unregister();
138
139
        if ($this->debug) {
140
            $registered->debug();
141
        }
142
143
        $registered->register();
144
    }
145
146
    /**
147
     * @param ContainerInterface $container
148
     * @return void
149
     * @throws ContainerExceptionInterface
150
     * @throws NotFoundExceptionInterface
151
     */
152
    private function afterRespond(ContainerInterface $container): void {
153
        /** @psalm-suppress MixedMethodCall */
154
        $container->get(StateResetter::class)->reset();
155
        gc_collect_cycles();
156
    }
157
158
    /**
159
     * Returns a new instance with the specified gRPC worker instance
160
     *
161
     * @return $this
162
     */
163
    public function withWorker(Worker $worker): self
164
    {
165
        $instance = clone $this;
166
        $instance->worker = $worker;
167
168
        return $instance;
169
    }
170
171
    /**
172
     * Transmitted services for registration gRPC server
173
     *
174
     * @param array $services Services array (key-value pairs)
175
     * ```php
176
     * [
177
     *      ServiceInterface::class => Service::class
178
     * ]
179
     * ```
180
     *
181
     * @return $this
182
     */
183
    public function setServices(array $services): self
184
    {
185
        $this->services = $services;
186
187
        return $this;
188
    }
189
190
    public function getServices(): array
191
    {
192
        return $this->services;
193
    }
194
195
    public function getWorker(): Worker
196
    {
197
        return $this->worker ?? Worker::create();
198
    }
199
200
    public function getInvoker(): InvokerInterface
201
    {
202
        return $this->invoker ?? new Invoker();
203
    }
204
}
205