From b3df4abcd8f3b72a422609c7aab10cad3a84e1d8 Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Mon, 13 May 2024 21:48:10 +0000 Subject: [PATCH 1/9] Fix already pending parent workflow --- src/WorkflowStub.php | 6 +++++- tests/Unit/WorkflowStubTest.php | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/WorkflowStub.php b/src/WorkflowStub.php index 2d76967..cc5392b 100644 --- a/src/WorkflowStub.php +++ b/src/WorkflowStub.php @@ -286,7 +286,11 @@ private function dispatch(): void ); } - $this->storedWorkflow->status->transitionTo(WorkflowPendingStatus::class); + try { + $this->storedWorkflow->status->transitionTo(WorkflowPendingStatus::class); + } catch (\Spatie\ModelStates\Exceptions\TransitionNotFound) { + // already running + } $dispatch = static::faked() ? 'dispatchSync' : 'dispatch'; diff --git a/tests/Unit/WorkflowStubTest.php b/tests/Unit/WorkflowStubTest.php index 904ebb7..d972d34 100644 --- a/tests/Unit/WorkflowStubTest.php +++ b/tests/Unit/WorkflowStubTest.php @@ -14,6 +14,7 @@ use Workflow\Serializers\Y; use Workflow\Signal; use Workflow\States\WorkflowCompletedStatus; +use Workflow\States\WorkflowFailedStatus; use Workflow\States\WorkflowPendingStatus; use Workflow\WorkflowStub; @@ -79,6 +80,23 @@ public function testComplete(): void $this->assertSame(1, $workflow->logs()->count()); } + public function testCompletePending(): void + { + Carbon::setTestNow('2022-01-01'); + + $workflow = WorkflowStub::make(TestAwaitWorkflow::class); + $workflow->start(); + WorkflowStub::getContext()->storedWorkflow->status->transitionTo(WorkflowPendingStatus::class); + $workflow->cancel(); + $workflow->fail(new Exception('resume')); + $workflow->resume(); + $this->assertSame('2022-01-01 00:00:00', WorkflowStub::now()->toDateTimeString()); + $this->assertSame(WorkflowCompletedStatus::class, $workflow->status()); + $this->assertSame('workflow', $workflow->output()); + $this->assertSame(1, $workflow->exceptions()->count()); + $this->assertSame(1, $workflow->logs()->count()); + } + public function testAwait(): void { $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); From 5b4c15dc44e76e86596fc213fe2bf815158421e1 Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Mon, 13 May 2024 21:53:38 +0000 Subject: [PATCH 2/9] ECS --- tests/Unit/WorkflowStubTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Unit/WorkflowStubTest.php b/tests/Unit/WorkflowStubTest.php index d972d34..e01d2fc 100644 --- a/tests/Unit/WorkflowStubTest.php +++ b/tests/Unit/WorkflowStubTest.php @@ -14,7 +14,6 @@ use Workflow\Serializers\Y; use Workflow\Signal; use Workflow\States\WorkflowCompletedStatus; -use Workflow\States\WorkflowFailedStatus; use Workflow\States\WorkflowPendingStatus; use Workflow\WorkflowStub; From 2a6b709c9343a2b2e18955b744dc9aae40c063cb Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Mon, 13 May 2024 22:22:03 +0000 Subject: [PATCH 3/9] Move logic --- src/Workflow.php | 8 ++++++-- src/WorkflowStub.php | 6 +----- tests/Unit/WorkflowStubTest.php | 17 ----------------- 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/Workflow.php b/src/Workflow.php index 3d7902c..9314d19 100644 --- a/src/Workflow.php +++ b/src/Workflow.php @@ -226,8 +226,12 @@ public function handle(): void ); if ($parentWorkflow) { - $parentWorkflow->toWorkflow() - ->next($parentWorkflow->pivot->parent_index, $this->now, $this->storedWorkflow->class, $return); + try { + $parentWorkflow->toWorkflow() + ->next($parentWorkflow->pivot->parent_index, $this->now, $this->storedWorkflow->class, $return); + } catch (\Spatie\ModelStates\Exceptions\TransitionNotFound) { + // already running + } } } } diff --git a/src/WorkflowStub.php b/src/WorkflowStub.php index cc5392b..2d76967 100644 --- a/src/WorkflowStub.php +++ b/src/WorkflowStub.php @@ -286,11 +286,7 @@ private function dispatch(): void ); } - try { - $this->storedWorkflow->status->transitionTo(WorkflowPendingStatus::class); - } catch (\Spatie\ModelStates\Exceptions\TransitionNotFound) { - // already running - } + $this->storedWorkflow->status->transitionTo(WorkflowPendingStatus::class); $dispatch = static::faked() ? 'dispatchSync' : 'dispatch'; diff --git a/tests/Unit/WorkflowStubTest.php b/tests/Unit/WorkflowStubTest.php index e01d2fc..904ebb7 100644 --- a/tests/Unit/WorkflowStubTest.php +++ b/tests/Unit/WorkflowStubTest.php @@ -79,23 +79,6 @@ public function testComplete(): void $this->assertSame(1, $workflow->logs()->count()); } - public function testCompletePending(): void - { - Carbon::setTestNow('2022-01-01'); - - $workflow = WorkflowStub::make(TestAwaitWorkflow::class); - $workflow->start(); - WorkflowStub::getContext()->storedWorkflow->status->transitionTo(WorkflowPendingStatus::class); - $workflow->cancel(); - $workflow->fail(new Exception('resume')); - $workflow->resume(); - $this->assertSame('2022-01-01 00:00:00', WorkflowStub::now()->toDateTimeString()); - $this->assertSame(WorkflowCompletedStatus::class, $workflow->status()); - $this->assertSame('workflow', $workflow->output()); - $this->assertSame(1, $workflow->exceptions()->count()); - $this->assertSame(1, $workflow->logs()->count()); - } - public function testAwait(): void { $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); From 50477aff52e6da0f4201e0720956d6ab43e98dd6 Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Tue, 14 May 2024 00:30:40 +0000 Subject: [PATCH 4/9] Add child workflow job --- src/ChildWorkflow.php | 44 +++++++++++++++++++++++++++++++++++++++++++ src/Workflow.php | 13 +++++++------ 2 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 src/ChildWorkflow.php diff --git a/src/ChildWorkflow.php b/src/ChildWorkflow.php new file mode 100644 index 0000000..682bf52 --- /dev/null +++ b/src/ChildWorkflow.php @@ -0,0 +1,44 @@ +onConnection($connection); + $this->onQueue($queue); + } + + public function handle() + { + $workflow = $this->parentWorkflow->toWorkflow(); + + try { + if ($this->parentWorkflow->logs()->whereIndex($this->index)->exists()) { + $workflow->resume(); + } else { + $workflow->next($this->index, $this->now, $this->storedWorkflow->class, $this->return); + } + } catch (\Spatie\ModelStates\Exceptions\TransitionNotFound) { + if ($workflow->running()) { + $this->release(); + } + } + + return $this->return; + } +} diff --git a/src/Workflow.php b/src/Workflow.php index 9314d19..c82743b 100644 --- a/src/Workflow.php +++ b/src/Workflow.php @@ -226,12 +226,13 @@ public function handle(): void ); if ($parentWorkflow) { - try { - $parentWorkflow->toWorkflow() - ->next($parentWorkflow->pivot->parent_index, $this->now, $this->storedWorkflow->class, $return); - } catch (\Spatie\ModelStates\Exceptions\TransitionNotFound) { - // already running - } + ChildWorkflow::dispatch( + $parentWorkflow->pivot->parent_index, + $this->now, + $this->storedWorkflow, + $return, + $parentWorkflow + ); } } } From d00f4886936f6b1fe64df69027310f05df4c9daf Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Tue, 14 May 2024 01:02:03 +0000 Subject: [PATCH 5/9] Add test --- tests/Unit/WorkflowTest.php | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/Unit/WorkflowTest.php b/tests/Unit/WorkflowTest.php index 9e81b54..7112ddd 100644 --- a/tests/Unit/WorkflowTest.php +++ b/tests/Unit/WorkflowTest.php @@ -108,4 +108,59 @@ public function testParent(): void $this->assertSame(WorkflowCompletedStatus::class, $childWorkflow->status()); $this->assertSame('other', $childWorkflow->output()); } + + public function testParentPending(): void + { + Carbon::setTestNow('2022-01-01'); + + $parentWorkflow = WorkflowStub::load(WorkflowStub::make(TestParentWorkflow::class)->id()); + + $storedParentWorkflow = StoredWorkflow::findOrFail($parentWorkflow->id()); + $storedParentWorkflow->arguments = Y::serialize([]); + $storedParentWorkflow->status = WorkflowPendingStatus::class; + $storedParentWorkflow->save(); + + $storedParentWorkflow->logs() + ->create([ + 'index' => 0, + 'now' => now(), + 'class' => TestChildWorkflow::class, + 'result' => Y::serialize('child_workflow'), + ]); + + $storedParentWorkflow->logs() + ->create([ + 'index' => 1, + 'now' => now(), + 'class' => TestActivity::class, + 'result' => Y::serialize('activity'), + ]); + + $childWorkflow = WorkflowStub::load(WorkflowStub::make(TestChildWorkflow::class)->id()); + + $storedChildWorkflow = StoredWorkflow::findOrFail($childWorkflow->id()); + $storedChildWorkflow->arguments = Y::serialize([]); + $storedChildWorkflow->status = WorkflowPendingStatus::class; + $storedChildWorkflow->save(); + $storedChildWorkflow->parents() + ->attach($storedParentWorkflow, [ + 'parent_index' => 0, + 'parent_now' => now(), + ]); + + $storedChildWorkflow->logs() + ->create([ + 'index' => 0, + 'now' => now(), + 'class' => TestOtherActivity::class, + 'result' => Y::serialize('other'), + ]); + + (new (TestChildWorkflow::class)($storedChildWorkflow))->handle(); + (new (TestParentWorkflow::class)($storedParentWorkflow))->handle(); + + $this->assertSame('2022-01-01 00:00:00', WorkflowStub::now()->toDateTimeString()); + $this->assertSame(WorkflowCompletedStatus::class, $childWorkflow->status()); + $this->assertSame('other', $childWorkflow->output()); + } } From 5b5fa0f8595b779297afa29cdfd4263581954a43 Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Tue, 14 May 2024 22:10:42 +0000 Subject: [PATCH 6/9] Refactor middleware --- src/Activity.php | 4 +-- src/ChildWorkflow.php | 15 ++++++++-- src/Exception.php | 29 +++++++++++++++---- ...wMiddleware.php => ActivityMiddleware.php} | 4 ++- ...areTest.php => ActivityMiddlewareTest.php} | 12 ++++---- tests/Unit/WorkflowTest.php | 13 ++++++--- 6 files changed, 56 insertions(+), 21 deletions(-) rename src/Middleware/{WorkflowMiddleware.php => ActivityMiddleware.php} (98%) rename tests/Unit/Middleware/{WorkflowMiddlewareTest.php => ActivityMiddlewareTest.php} (93%) diff --git a/src/Activity.php b/src/Activity.php index dec936e..bb230e0 100644 --- a/src/Activity.php +++ b/src/Activity.php @@ -18,8 +18,8 @@ use LimitIterator; use SplFileObject; use Throwable; +use Workflow\Middleware\ActivityMiddleware; use Workflow\Middleware\WithoutOverlappingMiddleware; -use Workflow\Middleware\WorkflowMiddleware; use Workflow\Models\StoredWorkflow; use Workflow\Serializers\Y; @@ -106,7 +106,7 @@ public function middleware() 0, $this->timeout ), - new WorkflowMiddleware(), + new ActivityMiddleware(), ]; } diff --git a/src/ChildWorkflow.php b/src/ChildWorkflow.php index 682bf52..5ad3654 100644 --- a/src/ChildWorkflow.php +++ b/src/ChildWorkflow.php @@ -4,10 +4,21 @@ namespace Workflow; +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldBeEncrypted; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Queue\SerializesModels; use Workflow\Models\StoredWorkflow; -class ChildWorkflow extends Activity +final class ChildWorkflow implements ShouldBeEncrypted, ShouldQueue { + use Dispatchable; + use InteractsWithQueue; + use Queueable; + use SerializesModels; + public function __construct( public int $index, public string $now, @@ -38,7 +49,5 @@ public function handle() $this->release(); } } - - return $this->return; } } diff --git a/src/Exception.php b/src/Exception.php index efb7a02..63f3240 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -4,10 +4,21 @@ namespace Workflow; +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldBeEncrypted; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Queue\SerializesModels; use Workflow\Models\StoredWorkflow; -class Exception extends Activity +final class Exception implements ShouldBeEncrypted, ShouldQueue { + use Dispatchable; + use InteractsWithQueue; + use Queueable; + use SerializesModels; + public function __construct( public int $index, public string $now, @@ -24,10 +35,18 @@ public function __construct( public function handle() { - if ($this->storedWorkflow->logs()->whereIndex($this->index)->exists()) { - return; - } + $workflow = $this->storedWorkflow->toWorkflow(); - return $this->exception; + try { + if ($this->storedWorkflow->logs()->whereIndex($this->index)->exists()) { + $workflow->resume(); + } else { + $workflow->next($this->index, $this->now, self::class, $this->exception); + } + } catch (\Spatie\ModelStates\Exceptions\TransitionNotFound) { + if ($workflow->running()) { + $this->release(); + } + } } } diff --git a/src/Middleware/WorkflowMiddleware.php b/src/Middleware/ActivityMiddleware.php similarity index 98% rename from src/Middleware/WorkflowMiddleware.php rename to src/Middleware/ActivityMiddleware.php index 7c69e62..f769722 100644 --- a/src/Middleware/WorkflowMiddleware.php +++ b/src/Middleware/ActivityMiddleware.php @@ -11,7 +11,7 @@ use Workflow\Events\ActivityFailed; use Workflow\Events\ActivityStarted; -final class WorkflowMiddleware +final class ActivityMiddleware { public function handle($job, $next): void { @@ -33,6 +33,7 @@ public function handle($job, $next): void try { $job->storedWorkflow->toWorkflow() ->next($job->index, $job->now, $job::class, $result); + ActivityCompleted::dispatch( $job->storedWorkflow->id, $uuid, @@ -59,6 +60,7 @@ public function handle($job, $next): void 'snippet' => array_slice(iterator_to_array($iterator), 0, 7), ]), now() ->format('Y-m-d\TH:i:s.u\Z')); + throw $throwable; } } diff --git a/tests/Unit/Middleware/WorkflowMiddlewareTest.php b/tests/Unit/Middleware/ActivityMiddlewareTest.php similarity index 93% rename from tests/Unit/Middleware/WorkflowMiddlewareTest.php rename to tests/Unit/Middleware/ActivityMiddlewareTest.php index 26037e0..9c387a4 100644 --- a/tests/Unit/Middleware/WorkflowMiddlewareTest.php +++ b/tests/Unit/Middleware/ActivityMiddlewareTest.php @@ -14,14 +14,14 @@ use Workflow\Events\ActivityCompleted; use Workflow\Events\ActivityFailed; use Workflow\Events\ActivityStarted; -use Workflow\Middleware\WorkflowMiddleware; +use Workflow\Middleware\ActivityMiddleware; use Workflow\Models\StoredWorkflow; use Workflow\States\WorkflowCompletedStatus; use Workflow\States\WorkflowRunningStatus; use Workflow\States\WorkflowWaitingStatus; use Workflow\WorkflowStub; -final class WorkflowMiddlewareTest extends TestCase +final class ActivityMiddlewareTest extends TestCase { public function testMiddleware(): void { @@ -42,7 +42,7 @@ public function testMiddleware(): void ->toDateTimeString(); $activity->storedWorkflow = $storedWorkflow; - $middleware = new WorkflowMiddleware(); + $middleware = new ActivityMiddleware(); $middleware->handle($activity, static function ($job) { return true; @@ -72,7 +72,7 @@ public function testAlreadyCompleted(): void ->toDateTimeString(); $activity->storedWorkflow = $storedWorkflow; - $middleware = new WorkflowMiddleware(); + $middleware = new ActivityMiddleware(); $middleware->handle($activity, static function ($job) { return true; @@ -106,7 +106,7 @@ public function testAlreadyRunning(): void ->toDateTimeString(); $activity->storedWorkflow = $storedWorkflow; - $middleware = new WorkflowMiddleware(); + $middleware = new ActivityMiddleware(); $middleware->handle($activity, static function ($job) { return true; @@ -137,7 +137,7 @@ public function testException(): void ->toDateTimeString(); $activity->storedWorkflow = $storedWorkflow; - $middleware = new WorkflowMiddleware(); + $middleware = new ActivityMiddleware(); try { $middleware->handle($activity, static function ($job) { diff --git a/tests/Unit/WorkflowTest.php b/tests/Unit/WorkflowTest.php index 7112ddd..d59b157 100644 --- a/tests/Unit/WorkflowTest.php +++ b/tests/Unit/WorkflowTest.php @@ -24,13 +24,16 @@ public function testException(): void { $exception = new \Exception('test'); $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); + $storedWorkflow = StoredWorkflow::findOrFail($workflow->id()); + $storedWorkflow->arguments = Y::serialize([]); + $storedWorkflow->save(); $activity = new Exception(0, now()->toDateTimeString(), StoredWorkflow::findOrFail( $workflow->id() ), $exception); - $result = $activity->handle(); + $activity->handle(); - $this->assertSame($exception, $result); + $this->assertSame(Exception::class, $storedWorkflow->logs()->first()->class); } public function testExceptionAlreadyLogged(): void @@ -38,6 +41,8 @@ public function testExceptionAlreadyLogged(): void $exception = new \Exception('test'); $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); $storedWorkflow = StoredWorkflow::findOrFail($workflow->id()); + $storedWorkflow->arguments = Y::serialize([]); + $storedWorkflow->save(); $activity = new Exception(0, now()->toDateTimeString(), StoredWorkflow::findOrFail( $workflow->id() ), $exception); @@ -50,9 +55,9 @@ public function testExceptionAlreadyLogged(): void 'result' => Y::serialize($exception), ]); - $result = $activity->handle(); + $activity->handle(); - $this->assertNull($result); + $this->assertSame(1, $storedWorkflow->logs()->count()); } public function testParent(): void From ac3404b32037e21c9f890cef7a1572b68e8e3af4 Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Tue, 14 May 2024 22:44:14 +0000 Subject: [PATCH 7/9] Refactor middleware --- src/ChildWorkflow.php | 6 ++++++ src/Exception.php | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/ChildWorkflow.php b/src/ChildWorkflow.php index 5ad3654..03b5e5c 100644 --- a/src/ChildWorkflow.php +++ b/src/ChildWorkflow.php @@ -19,6 +19,12 @@ final class ChildWorkflow implements ShouldBeEncrypted, ShouldQueue use Queueable; use SerializesModels; + public $tries = PHP_INT_MAX; + + public $maxExceptions = PHP_INT_MAX; + + public $timeout = 0; + public function __construct( public int $index, public string $now, diff --git a/src/Exception.php b/src/Exception.php index 63f3240..c3aa8ce 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -19,6 +19,12 @@ final class Exception implements ShouldBeEncrypted, ShouldQueue use Queueable; use SerializesModels; + public $tries = PHP_INT_MAX; + + public $maxExceptions = PHP_INT_MAX; + + public $timeout = 0; + public function __construct( public int $index, public string $now, From 34bafc8ef47128d8f5067e943baa5c34fc190e04 Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Fri, 17 May 2024 23:24:42 +0000 Subject: [PATCH 8/9] Add middleware --- src/ChildWorkflow.php | 7 +++++++ src/Exception.php | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/ChildWorkflow.php b/src/ChildWorkflow.php index 03b5e5c..f58b243 100644 --- a/src/ChildWorkflow.php +++ b/src/ChildWorkflow.php @@ -56,4 +56,11 @@ public function handle() } } } + + public function middleware() + { + return [ + new WithoutOverlappingMiddleware($this->parentWorkflow->id, WithoutOverlappingMiddleware::ACTIVITY), + ]; + } } diff --git a/src/Exception.php b/src/Exception.php index c3aa8ce..bda04c9 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -55,4 +55,11 @@ public function handle() } } } + + public function middleware() + { + return [ + new WithoutOverlappingMiddleware($this->storedWorkflow->id, WithoutOverlappingMiddleware::ACTIVITY), + ]; + } } From 892b1602af1523705d05b89a3da7d38257bd6047 Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Fri, 17 May 2024 23:39:55 +0000 Subject: [PATCH 9/9] Add middleware --- src/ChildWorkflow.php | 1 + src/Exception.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/ChildWorkflow.php b/src/ChildWorkflow.php index f58b243..d2e18ff 100644 --- a/src/ChildWorkflow.php +++ b/src/ChildWorkflow.php @@ -10,6 +10,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Workflow\Middleware\WithoutOverlappingMiddleware; use Workflow\Models\StoredWorkflow; final class ChildWorkflow implements ShouldBeEncrypted, ShouldQueue diff --git a/src/Exception.php b/src/Exception.php index bda04c9..3d7b4cd 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -10,6 +10,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Workflow\Middleware\WithoutOverlappingMiddleware; use Workflow\Models\StoredWorkflow; final class Exception implements ShouldBeEncrypted, ShouldQueue pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy