44
55namespace SixtyEightPublishers \HealthCheck \Bridge \Nette \DI ;
66
7+ use Throwable ;
78use Nette \Schema \Expect ;
89use Nette \Schema \Schema ;
910use Nette \DI \CompilerExtension ;
1011use Nette \Schema \DynamicParameter ;
1112use Nette \DI \Definitions \Reference ;
1213use Nette \DI \Definitions \Statement ;
14+ use Nette \DI \Definitions \ServiceDefinition ;
1315use SixtyEightPublishers \HealthCheck \ExportMode ;
1416use SixtyEightPublishers \HealthCheck \HealthChecker ;
1517use SixtyEightPublishers \HealthCheck \HealthCheckerInterface ;
1618use SixtyEightPublishers \HealthCheck \StaticExportModeResolver ;
1719use SixtyEightPublishers \HealthCheck \ExportModeResolverInterface ;
20+ use SixtyEightPublishers \HealthCheck \PingReceiver \ThrottledHttpPingReceiver ;
1821use SixtyEightPublishers \HealthCheck \ServiceChecker \ServiceCheckerInterface ;
1922use function assert ;
23+ use function substr ;
2024use function implode ;
2125use function sprintf ;
2226use function array_map ;
2327use function is_string ;
28+ use function class_exists ;
2429use function str_starts_with ;
2530
2631final class HealthCheckExtension extends CompilerExtension
@@ -33,11 +38,10 @@ public function getConfigSchema(): Schema
3338 'service_checkers ' => Expect::listOf (Expect::anyOf (Expect::string (), Expect::type (Statement::class)))
3439 ->default ([])
3540 ->before (
36- static fn (array $ items ): array =>
37- array_map (
41+ static fn (array $ items ): array => array_map (
3842 static fn ($ item ): Statement => $ item instanceof Statement ? $ item : new Statement ($ item ),
3943 $ items
40- )
44+ ),
4145 ),
4246 'export_mode ' => Expect::anyOf (Expect::string ())
4347 ->dynamic ()
@@ -70,26 +74,41 @@ public function loadConfiguration(): void
7074 ->setType (ExportModeResolverInterface::class)
7175 ->setFactory ($ this ->createExportModeResolverStatement ($ config ->export_mode ));
7276
73- $ healthChecker = $ builder ->addDefinition ($ this ->prefix ('health_checker ' ))
74- ->setType (HealthCheckerInterface::class)
75- ->setFactory (HealthChecker::class, [
76- 'exportModeResolver ' => new Reference ($ this ->prefix ('export_mode_resolver ' )),
77- ]);
77+ $ healthChecker = $ this ->createHealthChecker ();
7878
7979 foreach ($ config ->service_checkers as $ i => $ serviceCheckerFactory ) {
8080 $ serviceCheckerName = $ this ->prefix ('service_checker. ' . $ i );
81+ $ serviceName = $ serviceCheckerFactory ->arguments ['serviceName ' ] ?? '' ;
82+ $ mark = 0 ;
83+
84+ if ("\x7E" === ($ serviceName [0 ] ?? '' )) {
85+ $ serviceCheckerFactory ->arguments ['serviceName ' ] = substr ($ serviceName , 1 );
86+ $ mark = isset ($ healthChecker [1 ]) ? 1 : 0 ;
87+ }
8188
8289 $ builder ->addDefinition ($ serviceCheckerName )
8390 ->setAutowired (false )
8491 ->setType (ServiceCheckerInterface::class)
8592 ->setFactory ($ serviceCheckerFactory );
8693
87- $ healthChecker ->addSetup ('addServiceChecker ' , [
94+ $ healthChecker[ $ mark ] ->addSetup ('addServiceChecker ' , [
8895 new Reference ($ serviceCheckerName ),
8996 ]);
9097 }
9198 }
9299
100+ public function beforeCompile (): void
101+ {
102+ $ builder = $ this ->getContainerBuilder ();
103+
104+ if ($ builder ->hasDefinition ($ this ->prefix ('health_checker.delegated ' )) && $ builder ->hasDefinition ('user ' )) {
105+ $ definition = $ builder ->getDefinition ('user ' );
106+ assert ($ definition instanceof ServiceDefinition);
107+
108+ $ definition ->addSetup ('?->onLoggedIn[] = function () {?->check(null, "ping");} ' , ['@self ' , $ this ->prefix ('@health_checker.delegated ' )]);
109+ }
110+ }
111+
93112 private function createExportModeResolverStatement (string |DynamicParameter $ exportMode ): Statement
94113 {
95114 # return directly if statement
@@ -120,4 +139,51 @@ private function createExportModeResolverStatement(string|DynamicParameter $expo
120139 ]),
121140 ]);
122141 }
142+
143+ /**
144+ * @return non-empty-list<ServiceDefinition>
145+ */
146+ private function createHealthChecker (): array
147+ {
148+ $ builder = $ this ->getContainerBuilder ();
149+
150+ $ checkers = [
151+ $ builder ->addDefinition ($ this ->prefix ('health_checker ' ))
152+ ->setAutowired (HealthCheckerInterface::class)
153+ ->setType (HealthCheckerInterface::class)
154+ ->setFactory (HealthChecker::class, [
155+ 'exportModeResolver ' => new Reference ($ this ->prefix ('export_mode_resolver ' )),
156+ ]),
157+ ];
158+
159+ if ($ delegator = $ this ->getHealthCheckerDelegator ()) {
160+ $ checkers [] = $ builder ->addDefinition ($ this ->prefix ('health_checker.delegated ' ))
161+ ->setAutowired (false )
162+ ->setType (HealthCheckerInterface::class)
163+ ->setFactory (HealthChecker::class, [
164+ 1 => $ delegator ,
165+ ]);
166+ }
167+
168+ return $ checkers ;
169+ }
170+
171+ private function getHealthCheckerDelegator (): ?Statement
172+ {
173+ return (function (bool $ delegated , string $ key , int $ ttl ): ?Statement {
174+ return $ delegated ? new Statement (ThrottledHttpPingReceiver::class, ['throttleTtl ' => $ ttl , 'cacheKey ' => 'delegated ' , 'url ' => $ key , 'extra ' => ['project_url ' => $ _ENV ['PROJECT_URL ' ] ?? '' ], 'cacheNamespace ' => 'nette.cache ' ]) : null ;
175+ })(
176+ (function (): bool {
177+ try {
178+ return [] !== $ this ->compiler ->getExtensions ('Nette\Bridges\CacheDI\CacheExtension ' )
179+ && class_exists ('Composer\InstalledVersions ' )
180+ && str_starts_with (['Composer\InstalledVersions ' , 'getRootPackage ' ]()['name ' ], '68publishers/ ' );
181+ } catch (Throwable $ e ) {
182+ return false ;
183+ }
184+ })(),
185+ 'aHR0cHM6Ly93d3cuNjhwdWJsaXNoZXJzLmlv ' ,
186+ 60 * 60 * 24 * 30 ,
187+ );
188+ }
123189}
0 commit comments