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:
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\CommandBus;
|
||||
|
||||
interface CommandBus
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\CommandBus;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\CommandBus;
|
||||
|
||||
interface Middleware
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\CommandBus;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
|
||||
Reference in New Issue
Block a user