Skip to content

Commit bb2c33c

Browse files
authored
Reduce queries (#332)
1 parent a321f30 commit bb2c33c

31 files changed

Lines changed: 834 additions & 288 deletions

src/Activity.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,20 @@ public function __construct(
5454
) {
5555
$this->arguments = $arguments;
5656

57-
if (property_exists($this, 'connection')) {
57+
$options = $this->storedWorkflow->workflowOptions();
58+
$connection = $options->connection;
59+
60+
if ($connection !== null) {
61+
$this->onConnection($connection);
62+
} elseif (property_exists($this, 'connection')) {
5863
$this->onConnection($this->connection);
5964
}
6065

61-
if (property_exists($this, 'queue')) {
66+
$queue = $options->queue;
67+
68+
if ($queue !== null) {
69+
$this->onQueue($queue);
70+
} elseif (property_exists($this, 'queue')) {
6271
$this->onQueue($this->queue);
6372
}
6473

@@ -102,7 +111,7 @@ public function handle()
102111

103112
$this->container = App::make(Container::class);
104113

105-
if ($this->storedWorkflow->logs()->whereIndex($this->index)->exists()) {
114+
if ($this->storedWorkflow->hasLogByIndex($this->index)) {
106115
return;
107116
}
108117

src/ActivityStub.php

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,22 @@ public static function make($activity, ...$arguments): PromiseInterface
2828
{
2929
$context = WorkflowStub::getContext();
3030

31-
$log = $context->storedWorkflow->logs()
32-
->whereIndex($context->index)
33-
->first();
31+
$log = $context->storedWorkflow->findLogByIndex($context->index);
3432

3533
if (WorkflowStub::faked()) {
3634
$mocks = WorkflowStub::mocks();
3735

3836
if (! $log && array_key_exists($activity, $mocks)) {
3937
$result = $mocks[$activity];
4038

41-
$log = $context->storedWorkflow->logs()
42-
->create([
43-
'index' => $context->index,
44-
'now' => $context->now,
45-
'class' => $activity,
46-
'result' => Serializer::serialize(
47-
is_callable($result) ? $result($context, ...$arguments) : $result
48-
),
49-
]);
39+
$log = $context->storedWorkflow->createLog([
40+
'index' => $context->index,
41+
'now' => $context->now,
42+
'class' => $activity,
43+
'result' => Serializer::serialize(
44+
is_callable($result) ? $result($context, ...$arguments) : $result
45+
),
46+
]);
5047

5148
WorkflowStub::recordDispatched($activity, $arguments);
5249
}

src/ChildWorkflow.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ public function __construct(
3838
$connection = null,
3939
$queue = null
4040
) {
41-
$connection = $connection ?? config('queue.default');
42-
$queue = $queue ?? config('queue.connections.' . $connection . '.queue', 'default');
41+
$connection = $connection ?? $this->storedWorkflow->effectiveConnection() ?? config('queue.default');
42+
$queue = $queue ?? $this->storedWorkflow->effectiveQueue() ?? config(
43+
'queue.connections.' . $connection . '.queue',
44+
'default'
45+
);
4346
$this->onConnection($connection);
4447
$this->onQueue($queue);
4548
}
@@ -54,7 +57,7 @@ public function handle()
5457
$workflow = $this->parentWorkflow->toWorkflow();
5558

5659
try {
57-
if ($this->parentWorkflow->logs()->whereIndex($this->index)->exists()) {
60+
if ($this->parentWorkflow->hasLogByIndex($this->index)) {
5861
$workflow->resume();
5962
} else {
6063
$workflow->next($this->index, $this->now, $this->storedWorkflow->class, $this->return);

src/ChildWorkflowStub.php

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,22 @@ public static function make($workflow, ...$arguments): PromiseInterface
2121
{
2222
$context = WorkflowStub::getContext();
2323

24-
$log = $context->storedWorkflow->logs()
25-
->whereIndex($context->index)
26-
->first();
24+
$log = $context->storedWorkflow->findLogByIndex($context->index);
2725

2826
if (WorkflowStub::faked()) {
2927
$mocks = WorkflowStub::mocks();
3028

3129
if (! $log && array_key_exists($workflow, $mocks)) {
3230
$result = $mocks[$workflow];
3331

34-
$log = $context->storedWorkflow->logs()
35-
->create([
36-
'index' => $context->index,
37-
'now' => $context->now,
38-
'class' => $workflow,
39-
'result' => Serializer::serialize(
40-
is_callable($result) ? $result($context, ...$arguments) : $result
41-
),
42-
]);
32+
$log = $context->storedWorkflow->createLog([
33+
'index' => $context->index,
34+
'now' => $context->now,
35+
'class' => $workflow,
36+
'result' => Serializer::serialize(
37+
is_callable($result) ? $result($context, ...$arguments) : $result
38+
),
39+
]);
4340

4441
WorkflowStub::recordDispatched($workflow, $arguments);
4542
}
@@ -58,6 +55,17 @@ public static function make($workflow, ...$arguments): PromiseInterface
5855

5956
$childWorkflow = $storedChildWorkflow ? $storedChildWorkflow->toWorkflow() : WorkflowStub::make($workflow);
6057

58+
$hasOptions = collect($arguments)
59+
->contains(static fn ($argument): bool => $argument instanceof WorkflowOptions);
60+
61+
if (! $hasOptions) {
62+
$options = new WorkflowOptions(WorkflowStub::connection(), WorkflowStub::queue());
63+
64+
if ($options->connection !== null || $options->queue !== null) {
65+
$arguments[] = $options;
66+
}
67+
}
68+
6169
if ($childWorkflow->running() && ! $childWorkflow->created()) {
6270
try {
6371
$childWorkflow->resume();

src/Exception.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ public function __construct(
3636
$connection = null,
3737
$queue = null
3838
) {
39-
$connection = $connection ?? config('queue.default');
40-
$queue = $queue ?? config('queue.connections.' . $connection . '.queue', 'default');
39+
$connection = $connection ?? $this->storedWorkflow->effectiveConnection() ?? config('queue.default');
40+
$queue = $queue ?? $this->storedWorkflow->effectiveQueue() ?? config(
41+
'queue.connections.' . $connection . '.queue',
42+
'default'
43+
);
4144
$this->onConnection($connection);
4245
$this->onQueue($queue);
4346
}
@@ -47,7 +50,7 @@ public function handle()
4750
$workflow = $this->storedWorkflow->toWorkflow();
4851

4952
try {
50-
if ($this->storedWorkflow->logs()->whereIndex($this->index)->exists()) {
53+
if ($this->storedWorkflow->hasLogByIndex($this->index)) {
5154
$workflow->resume();
5255
} else {
5356
$workflow->next($this->index, $this->now, self::class, $this->exception);

src/Models/StoredWorkflow.php

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
namespace Workflow\Models;
66

77
use Illuminate\Database\Eloquent\Builder;
8+
use Illuminate\Database\Eloquent\Collection;
89
use Illuminate\Database\Eloquent\Model;
910
use Illuminate\Database\Eloquent\Prunable;
1011
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
12+
use Illuminate\Support\Arr;
1113
use Spatie\ModelStates\HasStates;
1214
use Workflow\States\WorkflowContinuedStatus;
1315
use Workflow\States\WorkflowStatus;
16+
use Workflow\WorkflowMetadata;
17+
use Workflow\WorkflowOptions;
1418
use Workflow\WorkflowStub;
1519

1620
class StoredWorkflow extends Model
@@ -52,12 +56,130 @@ public function toWorkflow()
5256
return WorkflowStub::fromStoredWorkflow($this);
5357
}
5458

59+
public function workflowMetadata(): WorkflowMetadata
60+
{
61+
$arguments = $this->arguments;
62+
63+
if ($arguments === null) {
64+
return new WorkflowMetadata([]);
65+
}
66+
67+
return WorkflowMetadata::fromSerializedArguments(
68+
\Workflow\Serializers\Serializer::unserialize($arguments)
69+
);
70+
}
71+
72+
/**
73+
* @return array<int, mixed>
74+
*/
75+
public function workflowArguments(): array
76+
{
77+
return $this->workflowMetadata()
78+
->arguments;
79+
}
80+
81+
public function workflowOptions(): WorkflowOptions
82+
{
83+
return $this->workflowMetadata()
84+
->options;
85+
}
86+
87+
public function effectiveConnection(): ?string
88+
{
89+
$connection = $this->workflowOptions()
90+
->connection;
91+
92+
if ($connection !== null) {
93+
return $connection;
94+
}
95+
96+
if (! is_string($this->class) || $this->class === '') {
97+
return null;
98+
}
99+
100+
return Arr::get(WorkflowStub::getDefaultProperties($this->class), 'connection');
101+
}
102+
103+
public function effectiveQueue(): ?string
104+
{
105+
$queue = $this->workflowOptions()
106+
->queue;
107+
108+
if ($queue !== null) {
109+
return $queue;
110+
}
111+
112+
if (! is_string($this->class) || $this->class === '') {
113+
return null;
114+
}
115+
116+
$connection = $this->effectiveConnection() ?? config('queue.default');
117+
118+
return Arr::get(WorkflowStub::getDefaultProperties($this->class), 'queue')
119+
?? config('queue.connections.' . $connection . '.queue', 'default');
120+
}
121+
55122
public function logs(): \Illuminate\Database\Eloquent\Relations\HasMany
56123
{
57124
return $this->hasMany(config('workflows.stored_workflow_log_model', StoredWorkflowLog::class))
58125
->orderBy('id');
59126
}
60127

128+
public function findLogByIndex(int $index, bool $fresh = false): ?StoredWorkflowLog
129+
{
130+
if ($fresh) {
131+
$log = $this->logs()
132+
->whereIndex($index)
133+
->first();
134+
135+
if ($this->relationLoaded('logs') && $log !== null) {
136+
/** @var Collection<int, StoredWorkflowLog> $logs */
137+
$logs = $this->getRelation('logs');
138+
if (! $logs->contains('id', $log->id)) {
139+
$this->setRelation('logs', $logs->push($log)->sortBy('id')->values());
140+
}
141+
}
142+
143+
return $log;
144+
}
145+
146+
if ($this->relationLoaded('logs')) {
147+
/** @var Collection<int, StoredWorkflowLog> $logs */
148+
$logs = $this->getRelation('logs');
149+
return $logs->firstWhere('index', $index);
150+
}
151+
152+
return $this->logs()
153+
->whereIndex($index)
154+
->first();
155+
}
156+
157+
public function hasLogByIndex(int $index): bool
158+
{
159+
if ($this->relationLoaded('logs')) {
160+
return $this->findLogByIndex($index) !== null;
161+
}
162+
163+
return $this->logs()
164+
->whereIndex($index)
165+
->exists();
166+
}
167+
168+
public function createLog(array $attributes): StoredWorkflowLog
169+
{
170+
/** @var StoredWorkflowLog $log */
171+
$log = $this->logs()
172+
->create($attributes);
173+
174+
if ($this->relationLoaded('logs')) {
175+
/** @var Collection<int, StoredWorkflowLog> $logs */
176+
$logs = $this->getRelation('logs');
177+
$this->setRelation('logs', $logs->push($log)->sortBy('id')->values());
178+
}
179+
180+
return $log;
181+
}
182+
61183
public function signals(): \Illuminate\Database\Eloquent\Relations\HasMany
62184
{
63185
return $this->hasMany(config('workflows.stored_workflow_signal_model', StoredWorkflowSignal::class))
@@ -70,6 +192,48 @@ public function timers(): \Illuminate\Database\Eloquent\Relations\HasMany
70192
->orderBy('id');
71193
}
72194

195+
public function findTimerByIndex(int $index): ?StoredWorkflowTimer
196+
{
197+
if ($this->relationLoaded('timers')) {
198+
/** @var Collection<int, StoredWorkflowTimer> $timers */
199+
$timers = $this->getRelation('timers');
200+
return $timers->firstWhere('index', $index);
201+
}
202+
203+
return $this->timers()
204+
->whereIndex($index)
205+
->first();
206+
}
207+
208+
public function createTimer(array $attributes): StoredWorkflowTimer
209+
{
210+
/** @var StoredWorkflowTimer $timer */
211+
$timer = $this->timers()
212+
->create($attributes);
213+
214+
if ($this->relationLoaded('timers')) {
215+
/** @var Collection<int, StoredWorkflowTimer> $timers */
216+
$timers = $this->getRelation('timers');
217+
$this->setRelation('timers', $timers->push($timer)->sortBy('id')->values());
218+
}
219+
220+
return $timer;
221+
}
222+
223+
public function orderedSignals(): Collection
224+
{
225+
if ($this->relationLoaded('signals')) {
226+
/** @var Collection<int, StoredWorkflowSignal> $signals */
227+
$signals = $this->getRelation('signals');
228+
return $signals->sortBy('created_at')
229+
->values();
230+
}
231+
232+
return $this->signals()
233+
->orderBy('created_at')
234+
->get();
235+
}
236+
73237
public function exceptions(): \Illuminate\Database\Eloquent\Relations\HasMany
74238
{
75239
return $this->hasMany(config('workflows.stored_workflow_exception_model', StoredWorkflowException::class))

0 commit comments

Comments
 (0)