- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
326 lines
8.7 KiB
PHP
326 lines
8.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Queue\Wrappers;
|
|
|
|
use App\Framework\Core\ValueObjects\Duration;
|
|
use App\Framework\Queue\Queue;
|
|
use App\Framework\Queue\RetryStrategyHelper;
|
|
use App\Framework\Queue\ValueObjects\JobMetadata;
|
|
use App\Framework\Queue\ValueObjects\JobPayload;
|
|
use App\Framework\Queue\ValueObjects\QueuePriority;
|
|
use App\Framework\Retry\RetryStrategy;
|
|
|
|
/**
|
|
* Event Queue Wrapper
|
|
*
|
|
* Specialized queue wrapper for event processing with type-safe operations
|
|
* Optimized for domain events, system events, and integration events
|
|
*/
|
|
final readonly class EventQueue
|
|
{
|
|
public function __construct(
|
|
private Queue $queue
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Push any object as an event
|
|
*
|
|
* @param object $event Any event object to be processed
|
|
* @param QueuePriority|null $priority Event priority (defaults to normal)
|
|
* @param Duration|null $delay Delay before processing (defaults to immediate)
|
|
* @param Duration|null $timeout Maximum processing time
|
|
* @param RetryStrategy|null $retryStrategy Custom retry strategy
|
|
*/
|
|
public function pushEvent(
|
|
object $event,
|
|
?QueuePriority $priority = null,
|
|
?Duration $delay = null,
|
|
?Duration $timeout = null,
|
|
?RetryStrategy $retryStrategy = null
|
|
): void {
|
|
$payload = JobPayload::create(
|
|
job: $event,
|
|
priority: $priority ?? QueuePriority::normal(),
|
|
delay: $delay ?? Duration::zero(),
|
|
timeout: $timeout ?? Duration::fromMinutes(2),
|
|
retryStrategy: $retryStrategy ?? RetryStrategyHelper::forEvents(),
|
|
metadata: JobMetadata::forEvent($event)
|
|
);
|
|
|
|
$this->queue->push($payload);
|
|
}
|
|
|
|
/**
|
|
* Push a domain event (high priority for business logic)
|
|
*/
|
|
public function pushDomainEvent(object $event): void
|
|
{
|
|
$this->pushEvent(
|
|
event: $event,
|
|
priority: QueuePriority::high(),
|
|
timeout: Duration::fromMinutes(1),
|
|
retryStrategy: RetryStrategyHelper::forEvents()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Push a system event (normal priority for system operations)
|
|
*/
|
|
public function pushSystemEvent(object $event): void
|
|
{
|
|
$this->pushEvent(
|
|
event: $event,
|
|
priority: QueuePriority::normal(),
|
|
timeout: Duration::fromMinutes(3),
|
|
retryStrategy: RetryStrategyHelper::forEvents()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Push an integration event (low priority, high retry tolerance)
|
|
*/
|
|
public function pushIntegrationEvent(object $event): void
|
|
{
|
|
$this->pushEvent(
|
|
event: $event,
|
|
priority: QueuePriority::low(),
|
|
timeout: Duration::fromMinutes(10),
|
|
retryStrategy: RetryStrategyHelper::forWebhooks()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Push a notification event (background processing)
|
|
*/
|
|
public function pushNotificationEvent(object $event): void
|
|
{
|
|
$this->pushEvent(
|
|
event: $event,
|
|
priority: QueuePriority::low(),
|
|
timeout: Duration::fromMinutes(5),
|
|
retryStrategy: RetryStrategyHelper::forEmails()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Push a delayed event (scheduled for future processing)
|
|
*/
|
|
public function pushDelayedEvent(object $event, Duration $delay): void
|
|
{
|
|
$this->pushEvent(
|
|
event: $event,
|
|
delay: $delay,
|
|
priority: QueuePriority::normal(),
|
|
timeout: Duration::fromMinutes(2)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Push a critical event (immediate processing, no retries)
|
|
*/
|
|
public function pushCriticalEvent(object $event): void
|
|
{
|
|
$this->pushEvent(
|
|
event: $event,
|
|
priority: QueuePriority::critical(),
|
|
timeout: Duration::fromSeconds(30),
|
|
retryStrategy: RetryStrategyHelper::none()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Pop the next event from the queue
|
|
*
|
|
* @return object|null The next event object or null if queue is empty
|
|
*/
|
|
public function popEvent(): ?object
|
|
{
|
|
$payload = $this->queue->pop();
|
|
|
|
return $payload?->job;
|
|
}
|
|
|
|
/**
|
|
* Peek at the next event without removing it
|
|
*
|
|
* @return object|null The next event object or null if queue is empty
|
|
*/
|
|
public function peekEvent(): ?object
|
|
{
|
|
$payload = $this->queue->peek();
|
|
|
|
return $payload?->job;
|
|
}
|
|
|
|
/**
|
|
* Pop the next event with its metadata
|
|
*
|
|
* @return JobPayload|null The complete job payload or null if queue is empty
|
|
*/
|
|
public function popEventWithMetadata(): ?JobPayload
|
|
{
|
|
return $this->queue->pop();
|
|
}
|
|
|
|
/**
|
|
* Get number of pending events
|
|
*/
|
|
public function size(): int
|
|
{
|
|
return $this->queue->size();
|
|
}
|
|
|
|
/**
|
|
* Check if queue is empty
|
|
*/
|
|
public function isEmpty(): bool
|
|
{
|
|
return $this->size() === 0;
|
|
}
|
|
|
|
/**
|
|
* Clear all events from queue
|
|
*
|
|
* @return int Number of events removed
|
|
*/
|
|
public function clear(): int
|
|
{
|
|
return $this->queue->clear();
|
|
}
|
|
|
|
/**
|
|
* Get event queue statistics
|
|
*/
|
|
public function getStats(): array
|
|
{
|
|
$stats = $this->queue->getStats();
|
|
|
|
return [
|
|
'type' => 'event',
|
|
'size' => $this->size(),
|
|
'is_empty' => $this->isEmpty(),
|
|
...$stats,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Batch push multiple events
|
|
*
|
|
* @param array<object> $events Array of event objects
|
|
* @param QueuePriority|null $priority Priority for all events
|
|
*/
|
|
public function pushBatch(array $events, ?QueuePriority $priority = null): void
|
|
{
|
|
foreach ($events as $event) {
|
|
$this->pushEvent($event, $priority);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Push events with different priorities based on event type
|
|
*
|
|
* @param array<object> $events Array of event objects
|
|
*/
|
|
public function pushSmartBatch(array $events): void
|
|
{
|
|
foreach ($events as $event) {
|
|
$this->pushEventByType($event);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Pop multiple events in batch
|
|
*
|
|
* @param int $count Maximum number of events to pop
|
|
* @return array<object> Array of event objects
|
|
*/
|
|
public function popBatch(int $count): array
|
|
{
|
|
$events = [];
|
|
|
|
for ($i = 0; $i < $count; $i++) {
|
|
$event = $this->popEvent();
|
|
|
|
if ($event === null) {
|
|
break;
|
|
}
|
|
|
|
$events[] = $event;
|
|
}
|
|
|
|
return $events;
|
|
}
|
|
|
|
/**
|
|
* Filter events by type/class
|
|
*
|
|
* @param string $eventClass The event class to filter by
|
|
* @return array<object> Events of the specified type
|
|
*/
|
|
public function getEventsByType(string $eventClass): array
|
|
{
|
|
$events = [];
|
|
$tempEvents = [];
|
|
|
|
// Pop all events temporarily
|
|
while (! $this->isEmpty()) {
|
|
$payload = $this->popEventWithMetadata();
|
|
if ($payload === null) {
|
|
break;
|
|
}
|
|
|
|
if ($payload->job instanceof $eventClass) {
|
|
$events[] = $payload->job;
|
|
} else {
|
|
$tempEvents[] = $payload;
|
|
}
|
|
}
|
|
|
|
// Push back non-matching events
|
|
foreach ($tempEvents as $payload) {
|
|
$this->queue->push($payload);
|
|
}
|
|
|
|
return $events;
|
|
}
|
|
|
|
/**
|
|
* Get events count by priority
|
|
*
|
|
* @return array<string, int> Priority name => count mapping
|
|
*/
|
|
public function getEventCountByPriority(): array
|
|
{
|
|
$stats = $this->getStats();
|
|
|
|
return $stats['priority_breakdown'] ?? [];
|
|
}
|
|
|
|
/**
|
|
* Push event with automatic priority based on event type
|
|
*/
|
|
private function pushEventByType(object $event): void
|
|
{
|
|
$className = get_class($event);
|
|
|
|
// Automatic priority assignment based on event name patterns
|
|
if (str_contains($className, 'Domain') || str_contains($className, 'Business')) {
|
|
$this->pushDomainEvent($event);
|
|
} elseif (str_contains($className, 'System') || str_contains($className, 'Application')) {
|
|
$this->pushSystemEvent($event);
|
|
} elseif (str_contains($className, 'Integration') || str_contains($className, 'External')) {
|
|
$this->pushIntegrationEvent($event);
|
|
} elseif (str_contains($className, 'Notification') || str_contains($className, 'Email')) {
|
|
$this->pushNotificationEvent($event);
|
|
} elseif (str_contains($className, 'Critical') || str_contains($className, 'Alert')) {
|
|
$this->pushCriticalEvent($event);
|
|
} else {
|
|
// Default to system event
|
|
$this->pushSystemEvent($event);
|
|
}
|
|
}
|
|
}
|