refactor(container): simplify Redis pool initialization flow

- Remove redundant `$container` parameter in `RedisPoolInitializer` instantiation.
- Streamline container interactions for improved clarity and maintainability.
This commit is contained in:
2025-11-04 02:43:45 +01:00
parent 315b54a209
commit 12afbe874d
13 changed files with 1216 additions and 95 deletions

View File

@@ -51,13 +51,15 @@ final readonly class AppBootstrapper
// Initialize environment with encryption support
$env = $this->initializeEnvironment();
// Workaround: If REDIS_PASSWORD_FILE is not set but expected file exists, set it manually
// This handles cases where Docker Compose doesn't set the variable correctly
$expectedRedisPasswordFile = '/run/secrets/redis_password';
if (!$env->has('REDIS_PASSWORD_FILE') && file_exists($expectedRedisPasswordFile)) {
// Add REDIS_PASSWORD_FILE to environment if file exists
$env = $env->withVariable('REDIS_PASSWORD_FILE', $expectedRedisPasswordFile);
}
#$expectedRedisPasswordFile = '/run/secrets/redis_password';
#if (!$env->has('REDIS_PASSWORD_FILE') && file_exists($expectedRedisPasswordFile)) {
# // Add REDIS_PASSWORD_FILE to environment if file exists
# #$env = $env->withVariable('REDIS_PASSWORD_FILE', $expectedRedisPasswordFile);
#
#}
// Make Environment available throughout the application
$this->container->instance(Environment::class, $env);
@@ -128,12 +130,13 @@ final readonly class AppBootstrapper
{
$this->collector->startTiming('bootstrap', PerformanceCategory::SYSTEM);
$this->bootstrapper->bootstrap($this->basePath, $this->collector);
// Get Environment from container (registered in constructor)
$env = $this->container->get(Environment::class);
$this->bootstrapper->bootstrap($this->basePath, $this->collector, $env);
$this->collector->endTiming('bootstrap');
// Initialize secrets management after container is bootstrapped
$env = $this->container->get(Environment::class);
$this->initializeSecretsManagement($env);
// ErrorHandler wird jetzt kontextabhängig registriert

View File

@@ -42,16 +42,17 @@ final readonly class ContainerBootstrapper
public function bootstrap(
string $basePath,
PerformanceCollectorInterface $collector,
Environment $environment,
): Container {
// Temporarily disable compiled container to fix bootstrap issues
// TODO: Re-enable once container interface compatibility is fixed
// $optimizedContainer = $this->tryLoadCompiledContainer($basePath, $collector);
// $optimizedContainer = $this->tryLoadCompiledContainer($basePath, $collector, $environment);
// if ($optimizedContainer !== null) {
// return $optimizedContainer;
// }
// Fallback to fresh container bootstrap
return $this->bootstrapFreshContainer($basePath, $collector);
return $this->bootstrapFreshContainer($basePath, $collector, $environment);
}
/**
@@ -59,7 +60,8 @@ final readonly class ContainerBootstrapper
*/
private function tryLoadCompiledContainer(
string $basePath,
PerformanceCollectorInterface $collector
PerformanceCollectorInterface $collector,
Environment $environment,
): ?Container {
try {
$cacheDir = sys_get_temp_dir() . '/framework-cache';
@@ -71,7 +73,7 @@ final readonly class ContainerBootstrapper
}
// Create temporary fresh container to validate against
$tempContainer = $this->createFreshContainer($basePath, $collector);
$tempContainer = $this->createFreshContainer($basePath, $collector, $environment);
// Create compiler for validation
$reflectionProvider = new CachedReflectionProvider();
@@ -86,8 +88,11 @@ final readonly class ContainerBootstrapper
// Load and return compiled container
$compiledContainer = ContainerCompiler::load($compiledPath);
// Environment must be registered first as runtime data that can't be compiled
$compiledContainer->instance(Environment::class, $environment);
// Add runtime instances that can't be compiled
$this->addRuntimeInstances($compiledContainer, $basePath, $collector);
$this->registerRuntimeServices($compiledContainer, $basePath, $collector, $environment);
return $compiledContainer;
@@ -108,9 +113,10 @@ final readonly class ContainerBootstrapper
*/
private function bootstrapFreshContainer(
string $basePath,
PerformanceCollectorInterface $collector
PerformanceCollectorInterface $collector,
Environment $environment,
): Container {
$container = $this->createFreshContainer($basePath, $collector);
$container = $this->createFreshContainer($basePath, $collector, $environment);
// Compile for next request (async in production)
$this->compileContainerAsync($container);
@@ -123,47 +129,87 @@ final readonly class ContainerBootstrapper
*/
private function createFreshContainer(
string $basePath,
PerformanceCollectorInterface $collector
PerformanceCollectorInterface $collector,
Environment $environment,
): DefaultContainer {
// Use the existing container or create new DefaultContainer
$container = $this->container instanceof DefaultContainer
? $this->container
: new DefaultContainer();
$this->addRuntimeInstances($container, $basePath, $collector);
// Environment must be registered first as it's required by other services
// Check if already registered (e.g. by AppBootstrapper) to avoid overwriting
if (! $container->has(Environment::class)) {
$container->instance(Environment::class, $environment);
}
$this->registerRuntimeServices($container, $basePath, $collector, $environment);
$this->autowire($container);
return $container;
}
/**
* Add instances that must be created at runtime
* Register all runtime services that must be created at runtime
*/
private function addRuntimeInstances(
private function registerRuntimeServices(
Container $container,
string $basePath,
PerformanceCollectorInterface $collector
PerformanceCollectorInterface $collector,
Environment $environment,
): void {
$this->registerCoreServices($container, $basePath, $collector);
$this->registerRedisAndCache($container, $collector, $environment);
$this->registerHttpServices($container);
$this->registerDatabaseServices($container, $environment);
}
/**
* Register core services: Clock, PathProvider, Logger, PerformanceCollector
*/
private function registerCoreServices(
Container $container,
string $basePath,
PerformanceCollectorInterface $collector,
): void {
// Core services that need runtime data
// Clock must be registered first as it's required by Logger
// Only create if not already registered (e.g. by ClockInitializer)
if (! $container->has(Clock::class)) {
$container->instance(Clock::class, new SystemClock());
}
$clock = $container->get(Clock::class);
$container->instance(PathProvider::class, new PathProvider($basePath));
$init = $container->get(LoggerInitializer::class);
$logger = $container->invoker->invoke(LoggerInitializer::class, '__invoke');
$container->instance(Logger::class, $logger);
$container->instance(PerformanceCollectorInterface::class, $collector);
$pool = new RedisPoolInitializer($container->get(Environment::class))->initialize();
$container->instance(Cache::class, new CacheInitializer($collector, $container, $pool)());
// Initialize Logger
$logger = $container->invoker->invoke(LoggerInitializer::class, '__invoke');
$container->instance(Logger::class, $logger);
}
/**
* Register Redis connection pool and Cache services
* Requires Environment to be registered in container
*/
private function registerRedisAndCache(
Container $container,
PerformanceCollectorInterface $collector,
Environment $environment,
): void {
$pool = new RedisPoolInitializer($environment)->initialize();
$container->instance(Cache::class, new CacheInitializer($collector, $container, $pool)());
}
/**
* Register HTTP-related services
*
* TODO: Remove manual Request binding once Discovery system properly handles RequestFactory Initializer
* The RequestFactory should be discovered via Initializer attribute and registered automatically
*/
private function registerHttpServices(Container $container): void {
$container->instance(ResponseEmitter::class, new ResponseEmitter());
// TEMPORARY FIX: Manual RequestFactory binding until Discovery issue is resolved
// TEMPORARY FIX: Manual Request binding until Discovery issue is resolved
// This should be handled by RequestFactory Initializer via Discovery system
$container->singleton(Request::class, function ($container) {
error_log("ContainerBootstrapper: Creating Request singleton");
@@ -179,13 +225,24 @@ final readonly class ContainerBootstrapper
return $request;
});
}
/**
* Register database-related services
*
* TODO: Remove manual DatabasePlatform binding once Discovery system properly handles DatabasePlatformInitializer
* The DatabasePlatformInitializer should be discovered via Initializer attribute and registered automatically
*/
private function registerDatabaseServices(
Container $container,
Environment $environment,
): void {
// TEMPORARY FIX: Manual DatabasePlatform binding until Initializer Discovery issue is resolved
$container->singleton(\App\Framework\Database\Platform\DatabasePlatform::class, function ($container) {
// This should be handled by DatabasePlatformInitializer via Discovery system
$container->singleton(\App\Framework\Database\Platform\DatabasePlatform::class, function ($container) use ($environment) {
error_log("ContainerBootstrapper: Creating DatabasePlatform singleton");
$env = $container->get(\App\Framework\Config\Environment::class);
$driver = $env->get('DB_DRIVER', 'pgsql');
$driver = $environment->get('DB_DRIVER', 'pgsql');
error_log("ContainerBootstrapper: DB_DRIVER = {$driver}");
@@ -200,7 +257,6 @@ final readonly class ContainerBootstrapper
return $platform;
});
}
/**