Lines
89.36%
42 / 47
Functions and Methods
66.66%
4 / 6
Classes and Traits
0.00%
0 / 1
| Name | Lines | Functions and Methods | CRAP | Classes and Traits | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| BrokerKernel | 89.36% | 42 / 47 | 66.66% | 4 / 6 | 11.15 | 0.00% | 0 / 1 | |||
| __construct | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| createBroker | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 1 | |||||
| buildSyntheticServicesFor | 100.00% | 17 / 17 | 100.00% | 1 / 1 | 1 | |||||
| buildNamedArgumentsFor | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | |||||
| warnAboutSlowInitializeCalls | 42.85% | 3 / 7 | 0.00% | 0 / 1 | 4.68 | |||||
| warnAboutReadyTimeoutBelowInitialize | 92.85% | 13 / 14 | 0.00% | 0 / 1 | 4.01 | |||||
| 1 | <?php | |
| 2 | ||
| 3 | declare(strict_types=1); | |
| 4 | ||
| 5 | namespace Stewart\Runtime\Kernel; | |
| 6 | ||
| 7 | use Psr\Log\LoggerInterface; | |
| 8 | use Stewart\Client\Connection\ConnectionConfig; | |
| 9 | use Stewart\Runtime\App\AppCatalog; | |
| 10 | use Stewart\Runtime\App\Collection\AppDefinitionCollection; | |
| 11 | use Stewart\Runtime\Broker\BrokerLifecycle; | |
| 12 | use Stewart\Runtime\Broker\OutboxLimits; | |
| 13 | use Stewart\Runtime\Config\CodegenConfig; | |
| 14 | use Stewart\Runtime\Config\ControlConfig; | |
| 15 | use Stewart\Runtime\Config\ExposeConfig; | |
| 16 | use Stewart\Runtime\Config\GitDeployConfig; | |
| 17 | use Stewart\Runtime\Config\HttpConfig; | |
| 18 | use Stewart\Runtime\Config\PersistenceConfig; | |
| 19 | use Stewart\Runtime\Config\ProjectRoot; | |
| 20 | use Stewart\Runtime\Config\ServiceCallPolicy; | |
| 21 | use Stewart\Runtime\Config\StewartConfig; | |
| 22 | use Stewart\Runtime\Config\SupervisionConfig; | |
| 23 | use Stewart\Runtime\Exception\ConfigurationException; | |
| 24 | use Stewart\Runtime\Model\StewartVersion; | |
| 25 | ||
| 26 | final readonly class BrokerKernel | |
| 27 | { | |
| 28 | public function __construct( | |
| 29 | private StewartVersion $stewartVersion, | |
| 30 | private string $userServicesFile, | |
| 31 | private ProjectRoot $projectRoot, | |
| 32 | private SyntheticServices $overrides = new SyntheticServices(), | |
| 33 | private ProfileCompiler $compiler = new ProfileCompiler(), | |
| 34 | ) {} | |
| 35 | ||
| 36 | /** @throws ConfigurationException */ | |
| 37 | public function createBroker(StewartConfig $config, AppCatalog $apps, LoggerInterface $logger, ?string $configFileOption = null): BrokerLifecycle | |
| 38 | { | |
| 39 | $this->warnAboutSlowInitializeCalls($config, $logger); | |
| 40 | $this->warnAboutReadyTimeoutBelowInitialize($config, $logger); | |
| 41 | ||
| 42 | return $this->compiler | |
| 43 | ->compileProfileContainer(ContainerProfile::Broker, $this->buildSyntheticServicesFor($config, $apps, $logger)->withOverrides($this->overrides), $this->buildNamedArgumentsFor($configFileOption)) | |
| 44 | ->resolveService(BrokerLifecycle::class); | |
| 45 | } | |
| 46 | ||
| 47 | /** @throws ConfigurationException */ | |
| 48 | private function buildSyntheticServicesFor(StewartConfig $config, AppCatalog $apps, LoggerInterface $logger): SyntheticServices | |
| 49 | { | |
| 50 | return new SyntheticServices() | |
| 51 | ->withService(StewartConfig::class, $config) | |
| 52 | ->withService(StewartVersion::class, $this->stewartVersion) | |
| 53 | ->withService(AppCatalog::class, $apps) | |
| 54 | ->withService(AppDefinitionCollection::class, $apps->enabled) | |
| 55 | ->withService(LoggerInterface::class, $logger) | |
| 56 | ->withService(ConnectionConfig::class, $config->requireHomeAssistant()) | |
| 57 | ->withService(SupervisionConfig::class, $config->supervision) | |
| 58 | ->withService(ServiceCallPolicy::class, $config->serviceCalls) | |
| 59 | ->withService(ControlConfig::class, $config->control) | |
| 60 | ->withService(HttpConfig::class, $config->http) | |
| 61 | ->withService(PersistenceConfig::class, $config->persistence) | |
| 62 | ->withService(ProjectRoot::class, $this->projectRoot) | |
| 63 | ->withService(CodegenConfig::class, $config->codegen) | |
| 64 | ->withService(GitDeployConfig::class, $config->gitDeploy) | |
| 65 | ->withService(ExposeConfig::class, $config->expose) | |
| 66 | ->withService(OutboxLimits::class, new OutboxLimits($config->workerEventBuffer, $config->workerStateBatch)); | |
| 67 | } | |
| 68 | ||
| 69 | private function buildNamedArgumentsFor(?string $configFileOption): NamedArguments | |
| 70 | { | |
| 71 | return new NamedArguments() | |
| 72 | ->withArgument('userServicesFile', $this->userServicesFile) | |
| 73 | ->withArgument('releaseCheckConfigFile', $configFileOption); | |
| 74 | } | |
| 75 | ||
| 76 | /** @throws ConfigurationException */ | |
| 77 | private function warnAboutSlowInitializeCalls(StewartConfig $config, LoggerInterface $logger): void | |
| 78 | { | |
| 79 | $initializeTimeout = $config->supervision->initializeTimeout->findDuration(); | |
| 80 | $commandTimeout = $config->requireHomeAssistant()->commandTimeout; | |
| 81 | ||
| 82 | if ($initializeTimeout !== null && $commandTimeout->isLongerThan($initializeTimeout)) { | |
| 83 | $logger->warning('An app initializing with a single slow service call will be dropped before that call times out', [ | |
| 84 | 'initialize_timeout' => (string) $initializeTimeout, | |
| 85 | 'command_timeout' => (string) $commandTimeout, | |
| 86 | ]); | |
| 87 | } | |
| 88 | } | |
| 89 | ||
| 90 | private function warnAboutReadyTimeoutBelowInitialize(StewartConfig $config, LoggerInterface $logger): void | |
| 91 | { | |
| 92 | $readyTimeout = $config->supervision->readyTimeout->findDuration(); | |
| 93 | $initializeTimeout = $config->supervision->initializeTimeout->findDuration(); | |
| 94 | ||
| 95 | if ($readyTimeout === null) { | |
| 96 | return; | |
| 97 | } | |
| 98 | ||
| 99 | if ($initializeTimeout === null) { | |
| 100 | $logger->warning('A hanging initialize() restarts its whole worker, because initialize_timeout is off while ready_timeout is on', [ | |
| 101 | 'ready_timeout' => (string) $readyTimeout, | |
| 102 | ]); | |
| 103 | ||
| 104 | return; | |
| 105 | } | |
| 106 | ||
| 107 | if (!$readyTimeout->isLongerThan($initializeTimeout)) { | |
| 108 | $logger->warning('A worker is restarted before an app that uses its whole initialize_timeout can report ready', [ | |
| 109 | 'initialize_timeout' => (string) $initializeTimeout, | |
| 110 | 'ready_timeout' => (string) $readyTimeout, | |
| 111 | ]); | |
| 112 | } | |
| 113 | } | |
| 114 | } |