Skip to content

Commit 4fa19d0

Browse files
committed
Merge SignalQueue into SignalDispatcher
1 parent 5a541d4 commit 4fa19d0

3 files changed

Lines changed: 111 additions & 158 deletions

File tree

src/Internal/Declaration/WorkflowInstance/SignalDispatcher.php

Lines changed: 110 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,37 @@
1919
use Temporal\Internal\Declaration\Prototype\WorkflowPrototype;
2020

2121
/**
22+
* @psalm-type Consumer = callable(ValuesInterface): mixed
23+
* @psalm-type OnSignalCallable = \Closure(non-empty-string $name, Consumer $handler, ValuesInterface $arguments): void
24+
*
2225
* @internal
2326
*/
2427
final class SignalDispatcher implements Destroyable
2528
{
2629
/** @var array<non-empty-string, SignalMethod> */
2730
private array $signalHandlers = [];
2831

29-
private readonly SignalQueue $signalQueue;
32+
/**
33+
* @var OnSignalCallable
34+
*/
35+
private \Closure $onSignal;
36+
37+
/**
38+
* @var array<int, SignalQueueItem>
39+
*/
40+
private array $queue = [];
41+
42+
/**
43+
* @var array<non-empty-string, Consumer>
44+
*/
45+
private array $consumers = [];
46+
47+
/**
48+
* A fallback consumer to handle signals when no consumer is attached.
49+
*
50+
* @var null|\Closure(non-empty-string, ValuesInterface): mixed
51+
*/
52+
private ?\Closure $dynamicConsumer = null;
3053

3154
/**
3255
* @param object $context Workflow instance.
@@ -35,16 +58,17 @@ public function __construct(
3558
WorkflowPrototype $prototype,
3659
private readonly object $context,
3760
) {
38-
$this->signalQueue = new SignalQueue();
39-
4061
foreach ($prototype->getSignalHandlers() as $definition) {
4162
$this->addFromSignalDefinition($definition);
4263
}
4364
}
4465

45-
public function getSignalQueue(): SignalQueue
66+
/**
67+
* @param OnSignalCallable $handler
68+
*/
69+
public function onSignal(\Closure $handler): void
4670
{
47-
return $this->signalQueue;
71+
$this->onSignal = $handler;
4872
}
4973

5074
/**
@@ -53,7 +77,7 @@ public function getSignalQueue(): SignalQueue
5377
*/
5478
public function getSignalHandler(string $name): \Closure
5579
{
56-
return fn(ValuesInterface $values) => $this->signalQueue->push($name, $values);
80+
return fn(ValuesInterface $values) => $this->push($name, $values);
5781
}
5882

5983
/**
@@ -67,7 +91,7 @@ public function addSignalHandler(string $name, callable $handler, string $descri
6791
$handler,
6892
$description,
6993
);
70-
$this->signalQueue->attach($name, $handler);
94+
$this->attach($name, $handler);
7195
}
7296

7397
public function addFromSignalDefinition(SignalDefinition $definition): void
@@ -79,20 +103,32 @@ public function addFromSignalDefinition(SignalDefinition $definition): void
79103
$handler,
80104
$definition->description,
81105
);
82-
$this->signalQueue->attach($name, $handler);
106+
$this->attach($name, $handler);
83107
}
84108

85109
/**
86110
* @param callable(non-empty-string, ValuesInterface): mixed $handler
87111
*/
88112
public function setDynamicSignalHandler(callable $handler): void
89113
{
90-
$this->signalQueue->setFallback($handler(...));
114+
$consumer = $handler(...);
115+
116+
$this->dynamicConsumer = $consumer;
117+
118+
// Flush all signals that have no consumer
119+
foreach ($this->queue as $k => $item) {
120+
if (\array_key_exists($item->name, $this->consumers)) {
121+
continue;
122+
}
123+
124+
unset($this->queue[$k]);
125+
$this->consumeFallback($item->name, $item->values);
126+
}
91127
}
92128

93129
public function clearSignalQueue(): void
94130
{
95-
$this->signalQueue->clear();
131+
$this->queue = [];
96132
}
97133

98134
/**
@@ -108,11 +144,10 @@ public function getSignalHandlers(): array
108144
->setDescription($handler->description);
109145
}
110146

111-
// todo
112-
// if ($this->dynamic !== null) {
113-
// $handlers[] = (new WorkflowInteractionDefinition())
114-
// ->setDescription('Dynamic signal handler');
115-
// }
147+
if ($this->dynamicConsumer !== null) {
148+
$handlers[] = (new WorkflowInteractionDefinition())
149+
->setDescription('Dynamic signal handler');
150+
}
116151

117152
\usort(
118153
$handlers,
@@ -127,8 +162,66 @@ public function getSignalHandlers(): array
127162

128163
public function destroy(): void
129164
{
130-
$this->signalQueue->clear();
131-
$this->signalQueue->destroy();
165+
$this->queue = [];
166+
$this->consumers = [];
167+
$this->dynamicConsumer = null;
168+
unset($this->onSignal);
132169
$this->signalHandlers = [];
133170
}
171+
172+
/**
173+
* @param non-empty-string $signal
174+
*/
175+
private function push(string $signal, ValuesInterface $values): void
176+
{
177+
if (isset($this->consumers[$signal])) {
178+
$this->consume($signal, $values, $this->consumers[$signal]);
179+
return;
180+
}
181+
182+
if ($this->dynamicConsumer !== null) {
183+
$this->consumeFallback($signal, $values);
184+
return;
185+
}
186+
187+
$this->queue[] = new SignalQueueItem($signal, $values);
188+
}
189+
190+
/**
191+
* @param non-empty-string $signal
192+
* @param Consumer $consumer
193+
*/
194+
private function attach(string $signal, callable $consumer): void
195+
{
196+
$this->consumers[$signal] = $consumer; // overwrite
197+
198+
foreach ($this->queue as $k => $item) {
199+
if ($item->name === $signal) {
200+
unset($this->queue[$k]);
201+
$this->consume($signal, $item->values, $consumer);
202+
}
203+
}
204+
}
205+
206+
/**
207+
* @param non-empty-string $signal
208+
* @param Consumer $consumer
209+
*/
210+
private function consume(string $signal, ValuesInterface $values, callable $consumer): void
211+
{
212+
($this->onSignal)($signal, $consumer, $values);
213+
}
214+
215+
/**
216+
* @param non-empty-string $signal
217+
*/
218+
private function consumeFallback(string $signal, ValuesInterface $values): void
219+
{
220+
$handler = $this->dynamicConsumer;
221+
\assert($handler !== null);
222+
223+
// Wrap the fallback consumer to call interceptors
224+
$consumer = static fn(ValuesInterface $values): mixed => $handler($signal, $values);
225+
($this->onSignal)($signal, $consumer, $values);
226+
}
134227
}

src/Internal/Declaration/WorkflowInstance/SignalQueue.php

Lines changed: 0 additions & 140 deletions
This file was deleted.

src/Internal/Workflow/Process/Process.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ static function () use ($handler, $inboundPipeline, $input): mixed {
126126
});
127127

128128
// Configure signal handler
129-
$workflowInstance->getSignalDispatcher()->getSignalQueue()->onSignal(
129+
$workflowInstance->getSignalDispatcher()->onSignal(
130130
function (string $name, callable $handler, ValuesInterface $arguments) use ($inboundPipeline): void {
131131
// Define Context for interceptors Pipeline
132132
Workflow::setCurrentContext($this->scopeContext);

0 commit comments

Comments
 (0)