Skip to content

Commit 8cec3bf

Browse files
committed
Add Swoole-specific optimizations to events Dispatcher
- Add listenersCache for prepared listeners (avoids creating new closures on every dispatch in long-running processes) - Use Context for deferred events state (coroutine-safe, prevents race conditions when multiple coroutines defer events simultaneously) - Invalidate listenersCache in listen(), setupWildcardListen(), forget()
1 parent 573d729 commit 8cec3bf

File tree

1 file changed

+48
-31
lines changed

1 file changed

+48
-31
lines changed

src/events/src/Dispatcher.php

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Closure;
88
use Exception;
9+
use Hypervel\Context\Context;
910
use Hypervel\Container\Container;
1011
use Hypervel\Contracts\Broadcasting\Factory as BroadcastFactory;
1112
use Hypervel\Contracts\Broadcasting\ShouldBroadcast;
@@ -58,6 +59,13 @@ class Dispatcher implements DispatcherContract
5859
*/
5960
protected array $wildcardsCache = [];
6061

62+
/**
63+
* The cached prepared listeners.
64+
*
65+
* @var array<string, array<Closure>>
66+
*/
67+
protected array $listenersCache = [];
68+
6169
/**
6270
* The queue resolver instance.
6371
*
@@ -72,23 +80,6 @@ class Dispatcher implements DispatcherContract
7280
*/
7381
protected $transactionManagerResolver;
7482

75-
/**
76-
* The currently deferred events.
77-
*/
78-
protected array $deferredEvents = [];
79-
80-
/**
81-
* Indicates if events should be deferred.
82-
*/
83-
protected bool $deferringEvents = false;
84-
85-
/**
86-
* The specific events to defer (null means defer all events).
87-
*
88-
* @var null|string[]
89-
*/
90-
protected ?array $eventsToDefer = null;
91-
9283
/**
9384
* Create a new event dispatcher instance.
9485
*/
@@ -131,6 +122,8 @@ public function listen(QueuedClosure|Closure|array|string $events, QueuedClosure
131122
$this->listeners[$event][] = $listener;
132123
}
133124
}
125+
126+
$this->listenersCache = [];
134127
}
135128

136129
/**
@@ -141,6 +134,7 @@ protected function setupWildcardListen(string $event, Closure|string|array $list
141134
$this->wildcards[$event][] = $listener;
142135

143136
$this->wildcardsCache = [];
137+
$this->listenersCache = [];
144138
}
145139

146140
/**
@@ -243,7 +237,12 @@ public function dispatch(string|object $event, mixed $payload = [], bool $halt =
243237
];
244238

245239
if ($this->shouldDeferEvent($parsedEvent)) {
246-
$this->deferredEvents[] = func_get_args();
240+
Context::override('__events.deferred_events', function (?array $events) use ($event, $payload, $halt) {
241+
$events = $events ?? [];
242+
$events[] = [$event, $payload, $halt];
243+
244+
return $events;
245+
});
247246

248247
return null;
249248
}
@@ -345,14 +344,20 @@ protected function broadcastEvent(ShouldBroadcast $event): void
345344
*/
346345
public function getListeners(string $eventName): array
347346
{
347+
if (isset($this->listenersCache[$eventName])) {
348+
return $this->listenersCache[$eventName];
349+
}
350+
348351
$listeners = array_merge(
349352
$this->prepareListeners($eventName),
350353
$this->wildcardsCache[$eventName] ?? $this->getWildcardListeners($eventName)
351354
);
352355

353-
return class_exists($eventName, false)
356+
$listeners = class_exists($eventName, false)
354357
? $this->addInterfaceListeners($eventName, $listeners)
355358
: $listeners;
359+
360+
return $this->listenersCache[$eventName] = $listeners;
356361
}
357362

358363
/**
@@ -657,6 +662,8 @@ public function forget(string $event): void
657662
unset($this->wildcardsCache[$key]);
658663
}
659664
}
665+
666+
$this->listenersCache = [];
660667
}
661668

662669
/**
@@ -720,29 +727,29 @@ public function setTransactionManagerResolver(callable $resolver): static
720727
*/
721728
public function defer(callable $callback, ?array $events = null): mixed
722729
{
723-
$wasDeferring = $this->deferringEvents;
724-
$previousDeferredEvents = $this->deferredEvents;
725-
$previousEventsToDefer = $this->eventsToDefer;
730+
$wasDeferring = Context::get('__events.deferring', false);
731+
$previousDeferredEvents = Context::get('__events.deferred_events', []);
732+
$previousEventsToDefer = Context::get('__events.events_to_defer', null);
726733

727-
$this->deferringEvents = true;
728-
$this->deferredEvents = [];
729-
$this->eventsToDefer = $events;
734+
Context::set('__events.deferring', true);
735+
Context::set('__events.deferred_events', []);
736+
Context::set('__events.events_to_defer', $events);
730737

731738
try {
732739
$result = $callback();
733740

734-
$this->deferringEvents = false;
741+
Context::set('__events.deferring', false);
735742

736743
/* @phpstan-ignore foreach.emptyArray (callback may add deferred events) */
737-
foreach ($this->deferredEvents as $args) {
744+
foreach (Context::get('__events.deferred_events', []) as $args) {
738745
$this->dispatch(...$args);
739746
}
740747

741748
return $result;
742749
} finally {
743-
$this->deferringEvents = $wasDeferring;
744-
$this->deferredEvents = $previousDeferredEvents;
745-
$this->eventsToDefer = $previousEventsToDefer;
750+
Context::set('__events.deferring', $wasDeferring);
751+
Context::set('__events.deferred_events', $previousDeferredEvents);
752+
Context::set('__events.events_to_defer', $previousEventsToDefer);
746753
}
747754
}
748755

@@ -751,7 +758,17 @@ public function defer(callable $callback, ?array $events = null): mixed
751758
*/
752759
protected function shouldDeferEvent(string $event): bool
753760
{
754-
return $this->deferringEvents && ($this->eventsToDefer === null || in_array($event, $this->eventsToDefer));
761+
if (! Context::get('__events.deferring', false)) {
762+
return false;
763+
}
764+
765+
$eventsToDefer = Context::get('__events.events_to_defer', null);
766+
767+
if ($eventsToDefer === null) {
768+
return true;
769+
}
770+
771+
return in_array($event, $eventsToDefer);
755772
}
756773

757774
/**

0 commit comments

Comments
 (0)