Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus;
interface CommandBus

View File

@@ -1,32 +1,41 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus;
use App\Framework\Context\ExecutionContext;
use App\Framework\DI\DefaultContainer;
use App\Framework\DI\Initializer;
use App\Framework\Discovery\Results\DiscoveryResults;
use App\Framework\Discovery\Results\DiscoveryRegistry;
use App\Framework\Logging\Logger;
use App\Framework\Queue\Queue;
final readonly class CommandBusInitializer
{
public function __construct(
private DefaultContainer $container,
private DiscoveryResults $results,
private DiscoveryRegistry $results,
private ExecutionContext $executionContext,
) {}
) {
}
#[Initializer]
public function __invoke(): CommandBus
public function __invoke(Logger $logger): CommandBus
{
$this->results->get(CommandHandler::class);
$handlerResults = $this->results->attributes->get(CommandHandler::class);
$handlers = [];
foreach($this->results->get(CommandHandler::class) as $handler) {
$handlers[] = CommandHandlerDescriptor::fromHandlerArray($handler);
foreach ($handlerResults as $discoveredAttribute) {
if ($discoveredAttribute->additionalData) {
$handlers[] = CommandHandlerDescriptor::fromHandlerArray($discoveredAttribute->additionalData);
}
}
$handlersCollection = new CommandHandlersCollection(...$handlers);
return new DefaultCommandBus($handlersCollection, $this->container, $this->executionContext);
// Resolve queue from container to avoid circular dependency
$queue = $this->container->get(Queue::class);
return new DefaultCommandBus($handlersCollection, $this->container, $this->executionContext, $queue, $logger);
}
}

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus;
@@ -8,5 +9,4 @@ use Attribute;
#[Attribute(\Attribute::TARGET_METHOD)]
final class CommandHandler
{
}

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus;

View File

@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus;
/**
@@ -12,7 +14,8 @@ final readonly class CommandHandlerDescriptor
public string $class,
public string $method,
public string $command,
) {}
) {
}
public static function fromHandlerArray(array $handler): self
{

View File

@@ -1,10 +1,12 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus;
use App\Framework\Core\AttributeMapper;
use ReflectionMethod;
use App\Framework\Reflection\WrappedReflectionClass;
use App\Framework\Reflection\WrappedReflectionMethod;
use RuntimeException;
final class CommandHandlerMapper implements AttributeMapper
@@ -14,20 +16,31 @@ final class CommandHandlerMapper implements AttributeMapper
return CommandHandler::class;
}
public function map(object $reflectionTarget, object $attributeInstance): ?array
public function map(WrappedReflectionClass|WrappedReflectionMethod $reflectionTarget, object $attributeInstance): ?array
{
if (!$reflectionTarget instanceof ReflectionMethod || !$attributeInstance instanceof CommandHandler) {
if (! $attributeInstance instanceof CommandHandler) {
return null;
}
if(empty($reflectionTarget->getParameters()[0])) {
// CommandHandler attributes are only valid on methods
if (! $reflectionTarget instanceof WrappedReflectionMethod) {
return null;
}
$parameters = $reflectionTarget->getParameters();
if ($parameters->isEmpty()) {
throw new RuntimeException('Missing Command-Type');
}
$firstParameter = $parameters->getFirst();
if ($firstParameter === null) {
throw new RuntimeException('Missing Command-Type');
}
return [
'class' => $reflectionTarget->getDeclaringClass()->getName(),
'class' => $reflectionTarget->getDeclaringClass()->getFullyQualified(),
'method' => $reflectionTarget->getName(),
'command' => $reflectionTarget->getParameters()[0]->getType()->getName(),
'command' => $firstParameter->getType(),
];
}
}

View File

@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus;
use ArrayIterator;
@@ -10,10 +12,11 @@ use Traversable;
final readonly class CommandHandlersCollection implements IteratorAggregate, Countable
{
private array $handlers;
public function __construct(
CommandHandlerDescriptor ...$handlers
#private array $handlers = []
){
) {
$handlerArray = [];
foreach ($handlers as $handler) {

View File

@@ -1,47 +1,48 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus;
use App\Application\Auth\LoginUser;
use App\Framework\CommandBus\Exceptions\NoHandlerFound;
use App\Framework\CommandBus\Middleware\DatabaseTransactionMiddleware;
use App\Framework\CommandBus\Middleware\PerformanceMonitoringMiddleware;
use App\Framework\Context\ExecutionContext;
use App\Framework\Context\ContextType;
use App\Framework\Context\ExecutionContext;
use App\Framework\DI\Container;
use App\Framework\DI\DefaultContainer;
use App\Framework\Queue\FileQueue;
use App\Framework\Logging\Logger;
use App\Framework\Queue\Queue;
use App\Framework\Queue\RedisQueue;
final readonly class DefaultCommandBus implements CommandBus
final class DefaultCommandBus implements CommandBus
{
public function __construct(
private CommandHandlersCollection $commandHandlers,
private Container $container,
private ExecutionContext $executionContext,
private Queue $queue = new RedisQueue(host: 'redis'),
private Queue $queue,
private Logger $logger,
private array $middlewares = [
PerformanceMonitoringMiddleware::class,
DatabaseTransactionMiddleware::class,
],
) {}
) {
}
public function dispatch(object $command): mixed
{
$contextType = $this->executionContext->getType();
error_log("CommandBus Debug: Execution context: {$contextType->value}");
error_log("CommandBus Debug: Context metadata: " . json_encode($this->executionContext->getMetadata()));
// Debug logging removed for production - only log errors
// Context-basierte Queue-Entscheidung
if ($this->shouldQueueInContext($command, $contextType)) {
error_log("CommandBus Debug: Job wird in Queue eingereiht: " . $command::class);
// No logging for normal queue operations in production
$this->queue->push($command);
return null;
}
error_log("CommandBus Debug: Job wird direkt ausgeführt: " . $command::class);
// No logging for normal direct execution in production
return $this->executeCommand($command);
}
@@ -50,13 +51,13 @@ final readonly class DefaultCommandBus implements CommandBus
$handlerExecutor = function (object $command): mixed {
$handler = $this->commandHandlers->get($command::class);
if($handler === null)
{
throw NoHandlerFound::forCommand($command::class);
if ($handler === null) {
throw NoHandlerFound::forCommand($command::class);
}
// $handler = $this->commandHandlers[get_class($command)];
$handlerClass = $this->container->get($handler->class);
return $handlerClass->{$handler->method}($command);
};
@@ -66,6 +67,7 @@ final readonly class DefaultCommandBus implements CommandBus
return function (object $command) use ($middlewareClass, $next): mixed {
/** @var Middleware $middleware */
$middleware = $this->container->get($middlewareClass);
return $middleware->handle($command, $next);
};
},
@@ -78,9 +80,9 @@ final readonly class DefaultCommandBus implements CommandBus
private function shouldQueueInContext(object $command, ContextType $context): bool
{
$ref = new \ReflectionClass($command);
$hasQueueAttribute = !empty($ref->getAttributes(ShouldQueue::class));
$hasQueueAttribute = ! empty($ref->getAttributes(ShouldQueue::class));
if (!$hasQueueAttribute) {
if (! $hasQueueAttribute) {
return false; // Ohne #[ShouldQueue] Attribut nie queuen
}
@@ -94,8 +96,6 @@ final readonly class DefaultCommandBus implements CommandBus
};
}
public function __debugInfo(): ?array
{
return $this->commandHandlers->toArray();

View File

@@ -1,8 +1,10 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus\Exceptions;
use App\Framework\Exception\ExceptionContext;
use App\Framework\Exception\FrameworkException;
final class NoHandlerFound extends FrameworkException
@@ -10,7 +12,9 @@ final class NoHandlerFound extends FrameworkException
public static function forCommand(string $commandClass): self
{
return new self(
"No handler found for command: $commandClass"
message: "No handler found for command: $commandClass",
context: ExceptionContext::forOperation('command_execution', 'CommandBus')
->withData(['command_class' => $commandClass])
);
}
}

View File

@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus;
interface Middleware

View File

@@ -1,12 +1,16 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus\Middleware;
use App\Framework\CommandBus\Middleware;
final readonly class DatabaseTransactionMiddleware implements Middleware
{
public function __construct() {}
public function __construct()
{
}
public function handle(object $command, callable $next): mixed
{
@@ -15,5 +19,4 @@ final readonly class DatabaseTransactionMiddleware implements Middleware
// Wenn die Validierung erfolgreich ist, wird der nächste Schritt aufgerufen
return $next($command);
}
}

View File

@@ -1,16 +1,18 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus\Middleware;
use App\Framework\CommandBus\Middleware;
use App\Framework\Logging\DefaultLogger;
use App\Framework\Logging\Logger;
final readonly class LoggingMiddleware implements Middleware
{
public function __construct(
private Logger $logger
) {}
) {
}
public function handle(object $command, callable $next): mixed
{

View File

@@ -1,24 +1,31 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus\Middleware;
use App\Framework\CommandBus\Middleware;
use App\Framework\Performance\Contracts\PerformanceCollectorInterface;
use App\Framework\Performance\PerformanceCategory;
use App\Framework\Performance\PerformanceMeter;
final readonly class PerformanceMonitoringMiddleware implements Middleware
{
public function __construct(
private PerformanceMeter $meter
) {}
private PerformanceCollectorInterface $collector
) {
}
public function handle(object $command, callable $next): mixed
{
$this->meter->startMeasure($command::class, PerformanceCategory::SYSTEM);
$commandKey = 'command_' . basename(str_replace('\\', '/', $command::class));
$this->collector->startTiming($commandKey, PerformanceCategory::SYSTEM, [
'command_class' => $command::class,
]);
$result = $next($command);
$this->meter->endMeasure($command::class);
$this->collector->endTiming($commandKey);
return $result;
}

View File

@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace App\Framework\CommandBus;
#[\Attribute(\Attribute::TARGET_CLASS)]