diff options
author | Valery Piashchynski <[email protected]> | 2021-01-26 11:52:03 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2021-01-26 11:52:03 +0300 |
commit | e2266b80db47444ba5858c736833a8a81b1361ad (patch) | |
tree | 37e06810352752f88032f7d0eadb554fa18b98da /tests/temporal/Workflow | |
parent | fae4711e3548bfd2e34f13aabfaab6a5b4e317c6 (diff) | |
parent | a392d962508e1bc9e497c8c4ef021425bc2c67c2 (diff) |
Merge pull request #502 from spiral/plugin/temporalv2.0.0-beta12
plugin(temporal): Add temporal plugins set to the RR2
Diffstat (limited to 'tests/temporal/Workflow')
41 files changed, 1457 insertions, 0 deletions
diff --git a/tests/temporal/Workflow/ActivityStubWorkflow.php b/tests/temporal/Workflow/ActivityStubWorkflow.php new file mode 100644 index 00000000..58dcdafb --- /dev/null +++ b/tests/temporal/Workflow/ActivityStubWorkflow.php @@ -0,0 +1,39 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class ActivityStubWorkflow +{ + #[WorkflowMethod(name: 'ActivityStubWorkflow')] + public function handler( + string $input + ) { + // typed stub + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + $result = []; + $result[] = yield $simple->echo($input); + + try { + $simple->undefined($input); + } catch (\BadMethodCallException $e) { + $result[] = 'invalid method call'; + } + + // untyped stub + $untyped = Workflow::newUntypedActivityStub(ActivityOptions::new()->withStartToCloseTimeout(1)); + + $result[] = yield $untyped->execute('SimpleActivity.echo', ['untyped']); + + return $result; + } +} diff --git a/tests/temporal/Workflow/AggregatedWorkflow.php b/tests/temporal/Workflow/AggregatedWorkflow.php new file mode 100644 index 00000000..3299179e --- /dev/null +++ b/tests/temporal/Workflow/AggregatedWorkflow.php @@ -0,0 +1,30 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Workflow; +use Temporal\Workflow\SignalMethod; +use Temporal\Workflow\WorkflowInterface; +use Temporal\Workflow\WorkflowMethod; + +#[WorkflowInterface] +class AggregatedWorkflow +{ + private array $values = []; + + #[SignalMethod] + public function addValue( + string $value + ) { + $this->values[] = $value; + } + + #[WorkflowMethod(name: 'AggregatedWorkflow')] + public function run( + int $count + ) { + yield Workflow::await(fn() => count($this->values) === $count); + + return $this->values; + } +} diff --git a/tests/temporal/Workflow/AsyncActivityWorkflow.php b/tests/temporal/Workflow/AsyncActivityWorkflow.php new file mode 100644 index 00000000..79e45dfb --- /dev/null +++ b/tests/temporal/Workflow/AsyncActivityWorkflow.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityCancellationType; +use Temporal\Activity\ActivityOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; + +#[Workflow\WorkflowInterface] +class AsyncActivityWorkflow +{ + #[WorkflowMethod(name: 'AsyncActivityWorkflow')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new() + ->withStartToCloseTimeout(20) + ->withCancellationType(ActivityCancellationType::WAIT_CANCELLATION_COMPLETED) + ); + + return yield $simple->external(); + } +} diff --git a/tests/temporal/Workflow/BinaryWorkflow.php b/tests/temporal/Workflow/BinaryWorkflow.php new file mode 100644 index 00000000..ed1952ad --- /dev/null +++ b/tests/temporal/Workflow/BinaryWorkflow.php @@ -0,0 +1,21 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\DataConverter\Bytes; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class BinaryWorkflow +{ + #[WorkflowMethod(name: 'BinaryWorkflow')] + public function handler( + Bytes $input + ): iterable { + $opts = ActivityOptions::new()->withStartToCloseTimeout(5); + + return yield Workflow::executeActivity('SimpleActivity.sha512', [$input], $opts); + } +} diff --git a/tests/temporal/Workflow/CancelSignalledChildWorkflow.php b/tests/temporal/Workflow/CancelSignalledChildWorkflow.php new file mode 100644 index 00000000..e2e43efa --- /dev/null +++ b/tests/temporal/Workflow/CancelSignalledChildWorkflow.php @@ -0,0 +1,57 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use React\Promise\Deferred; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class CancelSignalledChildWorkflow +{ + private array $status = []; + + #[Workflow\QueryMethod(name: 'getStatus')] + public function getStatus(): array + { + return $this->status; + } + + #[WorkflowMethod(name: 'CancelSignalledChildWorkflow')] + public function handler() + { + // typed stub + $simple = Workflow::newChildWorkflowStub(SimpleSignalledWorkflow::class); + + $waitSignalled = new Deferred(); + + $this->status[] = 'start'; + + // start execution + $scope = Workflow::newCancellationScope( + function () use ($simple, $waitSignalled) { + $call = $simple->handler(); + $this->status[] = 'child started'; + + yield $simple->add(8); + $this->status[] = 'child signalled'; + $waitSignalled->resolve(); + + return yield $call; + } + ); + + // only cancel scope when signal dispatched + yield $waitSignalled; + $scope->cancel(); + $this->status[] = 'scope cancelled'; + + try { + return yield $scope; + } catch (\Throwable $e) { + $this->status[] = 'process done'; + + return 'cancelled ok'; + } + } +} diff --git a/tests/temporal/Workflow/CanceledHeartbeatWorkflow.php b/tests/temporal/Workflow/CanceledHeartbeatWorkflow.php new file mode 100644 index 00000000..6b463192 --- /dev/null +++ b/tests/temporal/Workflow/CanceledHeartbeatWorkflow.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityCancellationType; +use Temporal\Activity\ActivityOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\HeartBeatActivity; + +#[Workflow\WorkflowInterface] +class CanceledHeartbeatWorkflow +{ + #[WorkflowMethod(name: 'CanceledHeartbeatWorkflow')] + public function handler(): iterable + { + $act = Workflow::newActivityStub( + HeartBeatActivity::class, + ActivityOptions::new() + ->withStartToCloseTimeout(50) + ->withCancellationType(ActivityCancellationType::WAIT_CANCELLATION_COMPLETED) + ->withHeartbeatTimeout(1) + ); + + return yield $act->slow('test'); + } +} diff --git a/tests/temporal/Workflow/CancelledMidflightWorkflow.php b/tests/temporal/Workflow/CancelledMidflightWorkflow.php new file mode 100644 index 00000000..ea799ce1 --- /dev/null +++ b/tests/temporal/Workflow/CancelledMidflightWorkflow.php @@ -0,0 +1,47 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class CancelledMidflightWorkflow +{ + private array $status = []; + + #[Workflow\QueryMethod(name: 'getStatus')] + public function getStatus(): array + { + return $this->status; + } + + #[WorkflowMethod(name: 'CancelledMidflightWorkflow')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + $this->status[] = 'start'; + + $scope = Workflow::newCancellationScope( + function () use ($simple) { + $this->status[] = 'in scope'; + $simple->slow('1'); + } + )->onCancel( + function () { + $this->status[] = 'on cancel'; + } + ); + + $scope->cancel(); + $this->status[] = 'done cancel'; + + return 'OK'; + } +} diff --git a/tests/temporal/Workflow/CancelledNestedWorkflow.php b/tests/temporal/Workflow/CancelledNestedWorkflow.php new file mode 100644 index 00000000..0c82f761 --- /dev/null +++ b/tests/temporal/Workflow/CancelledNestedWorkflow.php @@ -0,0 +1,72 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Exception\Failure\CanceledFailure; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class CancelledNestedWorkflow +{ + private array $status = []; + + #[Workflow\QueryMethod(name: 'getStatus')] + public function getStatus(): array + { + return $this->status; + } + + #[WorkflowMethod(name: 'CancelledNestedWorkflow')] + public function handler() + { + $this->status[] = 'begin'; + try { + yield Workflow::newCancellationScope( + function () { + $this->status[] = 'first scope'; + + $scope = Workflow::newCancellationScope( + function () { + $this->status[] = 'second scope'; + + try { + yield Workflow::timer(2); + } catch (CanceledFailure $e) { + $this->status[] = 'second scope cancelled'; + throw $e; + } + + $this->status[] = 'second scope done'; + } + )->onCancel( + function () { + $this->status[] = 'close second scope'; + } + ); + + try { + yield Workflow::timer(1); + } catch (CanceledFailure $e) { + $this->status[] = 'first scope cancelled'; + throw $e; + } + + $this->status[] = 'first scope done'; + + yield $scope; + } + )->onCancel( + function () { + $this->status[] = 'close first scope'; + } + ); + } catch (CanceledFailure $e) { + $this->status[] = 'close process'; + + return 'CANCELLED'; + } + + return 'OK'; + } +} diff --git a/tests/temporal/Workflow/CancelledScopeWorkflow.php b/tests/temporal/Workflow/CancelledScopeWorkflow.php new file mode 100644 index 00000000..50e0992f --- /dev/null +++ b/tests/temporal/Workflow/CancelledScopeWorkflow.php @@ -0,0 +1,39 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; + +#[Workflow\WorkflowInterface] +class CancelledScopeWorkflow +{ + #[WorkflowMethod(name: 'CancelledScopeWorkflow')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + $cancelled = 'not'; + + $scope = Workflow::newCancellationScope( + function () use ($simple) { + yield Workflow::timer(2); + yield $simple->slow('hello'); + } + )->onCancel( + function () use (&$cancelled) { + $cancelled = 'yes'; + } + ); + + yield Workflow::timer(1); + $scope->cancel(); + + return $cancelled; + } +} diff --git a/tests/temporal/Workflow/CancelledSingleScopeWorkflow.php b/tests/temporal/Workflow/CancelledSingleScopeWorkflow.php new file mode 100644 index 00000000..5fe8d3d8 --- /dev/null +++ b/tests/temporal/Workflow/CancelledSingleScopeWorkflow.php @@ -0,0 +1,55 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Exception\Failure\CanceledFailure; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; + +#[Workflow\WorkflowInterface] +class CancelledSingleScopeWorkflow +{ + private array $status = []; + + #[Workflow\QueryMethod(name: 'getStatus')] + public function getStatus(): array + { + return $this->status; + } + + #[WorkflowMethod(name: 'CancelledSingleScopeWorkflow')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new() + ->withStartToCloseTimeout(5) + ); + + $this->status[] = 'start'; + try { + yield Workflow::newCancellationScope( + function () use ($simple) { + try { + $this->status[] = 'in scope'; + yield $simple->slow('1'); + } catch (CanceledFailure $e) { + // after process is complete, do not use for business logic + $this->status[] = 'captured in scope'; + throw $e; + } + } + )->onCancel( + function () { + $this->status[] = 'on cancel'; + } + ); + } catch (CanceledFailure $e) { + $this->status[] = 'captured in process'; + } + + return 'OK'; + } +} diff --git a/tests/temporal/Workflow/CancelledWithCompensationWorkflow.php b/tests/temporal/Workflow/CancelledWithCompensationWorkflow.php new file mode 100644 index 00000000..2074aac1 --- /dev/null +++ b/tests/temporal/Workflow/CancelledWithCompensationWorkflow.php @@ -0,0 +1,79 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Exception\Failure\CanceledFailure; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class CancelledWithCompensationWorkflow +{ + private array $status = []; + + #[Workflow\QueryMethod(name: 'getStatus')] + public function getStatus(): array + { + return $this->status; + } + + #[WorkflowMethod(name: 'CancelledWithCompensationWorkflow')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + // waits for 2 seconds + $slow = $simple->slow('DOING SLOW ACTIVITY'); + + try { + $this->status[] = 'yield'; + $result = yield $slow; + } catch (CanceledFailure $e) { + $this->status[] = 'rollback'; + + try { + // must fail again + $result = yield $slow; + } catch (CanceledFailure $e) { + $this->status[] = 'captured retry'; + } + + try { + // fail since on cancelled context + $result = yield $simple->echo('echo must fail'); + } catch (CanceledFailure $e) { + $this->status[] = 'captured promise on cancelled'; + } + + $scope = Workflow::newDetachedCancellationScope( + function () use ($simple) { + $this->status[] = 'START rollback'; + + $second = yield $simple->echo('rollback'); + + $this->status[] = sprintf("RESULT (%s)", $second); + + if ($second !== 'ROLLBACK') { + $this->status[] = 'FAIL rollback'; + return 'failed to compensate ' . $second; + } + $this->status[] = 'DONE rollback'; + + return 'OK'; + } + ); + + $this->status[] = 'WAIT ROLLBACK'; + $result = yield $scope; + $this->status[] = 'COMPLETE rollback'; + } + + $this->status[] = 'result: ' . $result; + return $result; + } +} diff --git a/tests/temporal/Workflow/CancelledWorkflow.php b/tests/temporal/Workflow/CancelledWorkflow.php new file mode 100644 index 00000000..be9f7542 --- /dev/null +++ b/tests/temporal/Workflow/CancelledWorkflow.php @@ -0,0 +1,31 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Exception\Failure\CanceledFailure; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class CancelledWorkflow +{ + #[WorkflowMethod(name: 'CancelledWorkflow')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + // waits for 2 seconds + $slow = $simple->slow('DOING SLOW ACTIVITY'); + + try { + return yield $slow; + } catch (CanceledFailure $e) { + return "CANCELLED"; + } + } +} diff --git a/tests/temporal/Workflow/ChainedWorkflow.php b/tests/temporal/Workflow/ChainedWorkflow.php new file mode 100644 index 00000000..ba9c8f96 --- /dev/null +++ b/tests/temporal/Workflow/ChainedWorkflow.php @@ -0,0 +1,31 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class ChainedWorkflow +{ + #[WorkflowMethod(name: 'ChainedWorkflow')] + public function handler(string $input): iterable + { + $opts = ActivityOptions::new()->withStartToCloseTimeout(5); + + return yield Workflow::executeActivity( + 'SimpleActivity.echo', + [$input], + $opts + )->then(function ($result) use ($opts) { + return Workflow::executeActivity( + 'SimpleActivity.lower', + ['Result:' . $result], + $opts + ); + }); + } +} diff --git a/tests/temporal/Workflow/ChildStubWorkflow.php b/tests/temporal/Workflow/ChildStubWorkflow.php new file mode 100644 index 00000000..608962c2 --- /dev/null +++ b/tests/temporal/Workflow/ChildStubWorkflow.php @@ -0,0 +1,30 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class ChildStubWorkflow +{ + #[WorkflowMethod(name: 'ChildStubWorkflow')] + public function handler( + string $input + ) { + // typed stub + $simple = Workflow::newChildWorkflowStub(SimpleWorkflow::class); + + $result = []; + $result[] = yield $simple->handler($input); + + // untyped + $untyped = Workflow::newUntypedChildWorkflowStub('SimpleWorkflow'); + $result[] = yield $untyped->execute(['untyped']); + + $execution = yield $untyped->getExecution(); + assert($execution instanceof Workflow\WorkflowExecution); + + return $result; + } +} diff --git a/tests/temporal/Workflow/ComplexExceptionalWorkflow.php b/tests/temporal/Workflow/ComplexExceptionalWorkflow.php new file mode 100644 index 00000000..bf65ccb2 --- /dev/null +++ b/tests/temporal/Workflow/ComplexExceptionalWorkflow.php @@ -0,0 +1,26 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Common\RetryOptions; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class ComplexExceptionalWorkflow +{ + #[WorkflowMethod(name: 'ComplexExceptionalWorkflow')] + public function handler() + { + $child = Workflow::newChildWorkflowStub( + ExceptionalActivityWorkflow::class, + Workflow\ChildWorkflowOptions::new()->withRetryOptions( + (new RetryOptions())->withMaximumAttempts(1) + ) + ); + + return yield $child->handler(); + } +} diff --git a/tests/temporal/Workflow/ContinuableWorkflow.php b/tests/temporal/Workflow/ContinuableWorkflow.php new file mode 100644 index 00000000..78411414 --- /dev/null +++ b/tests/temporal/Workflow/ContinuableWorkflow.php @@ -0,0 +1,38 @@ +<?php + + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; + +#[Workflow\WorkflowInterface] +class ContinuableWorkflow +{ + #[WorkflowMethod(name: 'ContinuableWorkflow')] + public function handler( + int $generation + ) { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + if ($generation > 5) { + // complete + return "OK" . $generation; + } + + if ($generation !== 1) { + assert(!empty(Workflow::getInfo()->continuedExecutionRunId)); + } + + for ($i = 0; $i < $generation; $i++) { + yield $simple->echo((string)$generation); + } + + return Workflow::continueAsNew('ContinuableWorkflow', [++$generation]); + } +} diff --git a/tests/temporal/Workflow/EmptyWorkflow.php b/tests/temporal/Workflow/EmptyWorkflow.php new file mode 100644 index 00000000..57fb5e65 --- /dev/null +++ b/tests/temporal/Workflow/EmptyWorkflow.php @@ -0,0 +1,16 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Workflow\WorkflowMethod; +use Temporal\Workflow; + +#[Workflow\WorkflowInterface] +class EmptyWorkflow +{ + #[WorkflowMethod] + public function handler() + { + return 42; + } +} diff --git a/tests/temporal/Workflow/ExceptionalActivityWorkflow.php b/tests/temporal/Workflow/ExceptionalActivityWorkflow.php new file mode 100644 index 00000000..e0ed0005 --- /dev/null +++ b/tests/temporal/Workflow/ExceptionalActivityWorkflow.php @@ -0,0 +1,25 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Common\RetryOptions; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class ExceptionalActivityWorkflow +{ + #[WorkflowMethod(name: 'ExceptionalActivityWorkflow')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ->withRetryOptions((new RetryOptions())->withMaximumAttempts(1)) + ); + + return yield $simple->fail(); + } +} diff --git a/tests/temporal/Workflow/ExceptionalWorkflow.php b/tests/temporal/Workflow/ExceptionalWorkflow.php new file mode 100644 index 00000000..9a3e907f --- /dev/null +++ b/tests/temporal/Workflow/ExceptionalWorkflow.php @@ -0,0 +1,18 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class ExceptionalWorkflow +{ + #[WorkflowMethod(name: 'ExceptionalWorkflow')] + public function handler() + { + throw new \RuntimeException("workflow error"); + } +} diff --git a/tests/temporal/Workflow/FailedHeartbeatWorkflow.php b/tests/temporal/Workflow/FailedHeartbeatWorkflow.php new file mode 100644 index 00000000..e857f100 --- /dev/null +++ b/tests/temporal/Workflow/FailedHeartbeatWorkflow.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Common\RetryOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\HeartBeatActivity; + +#[Workflow\WorkflowInterface] +class FailedHeartbeatWorkflow +{ + #[WorkflowMethod(name: 'FailedHeartbeatWorkflow')] + public function handler( + int $iterations + ): iterable { + $act = Workflow::newActivityStub( + HeartBeatActivity::class, + ActivityOptions::new() + ->withStartToCloseTimeout(50) + // will fail on first attempt + ->withRetryOptions(RetryOptions::new()->withMaximumAttempts(2)) + ); + + return yield $act->failedActivity($iterations); + } +} diff --git a/tests/temporal/Workflow/LoopWithSignalCoroutinesWorkflow.php b/tests/temporal/Workflow/LoopWithSignalCoroutinesWorkflow.php new file mode 100644 index 00000000..c389fd78 --- /dev/null +++ b/tests/temporal/Workflow/LoopWithSignalCoroutinesWorkflow.php @@ -0,0 +1,55 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; +use Temporal\Workflow\SignalMethod; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class LoopWithSignalCoroutinesWorkflow +{ + private array $values = []; + private array $result = []; + private $simple; + + public function __construct() + { + $this->simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + } + + #[SignalMethod] + public function addValue( + string $value + ) { + $value = yield $this->simple->prefix('in signal ', $value); + $value = yield $this->simple->prefix('in signal 2 ', $value); + + $this->values[] = $value; + } + + #[WorkflowMethod(name: 'LoopWithSignalCoroutinesWorkflow')] + public function run( + int $count + ) { + while (true) { + yield Workflow::await(fn() => $this->values !== []); + $value = array_shift($this->values); + + // uppercases + $this->result[] = yield $this->simple->echo($value); + + if (count($this->result) === $count) { + break; + } + } + + asort($this->result); + return array_values($this->result); + } +} diff --git a/tests/temporal/Workflow/LoopWorkflow.php b/tests/temporal/Workflow/LoopWorkflow.php new file mode 100644 index 00000000..97d7a3aa --- /dev/null +++ b/tests/temporal/Workflow/LoopWorkflow.php @@ -0,0 +1,51 @@ +<?php + + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; +use Temporal\Workflow\SignalMethod; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class LoopWorkflow +{ + private array $values = []; + private array $result = []; + private $simple; + + public function __construct() + { + $this->simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + } + + #[SignalMethod] + public function addValue( + string $value + ) { + $this->values[] = $value; + } + + #[WorkflowMethod(name: 'LoopWorkflow')] + public function run( + int $count + ) { + while (true) { + yield Workflow::await(fn() => $this->values !== []); + $value = array_shift($this->values); + + $this->result[] = yield $this->simple->echo($value); + + if (count($this->result) === $count) { + break; + } + } + + return $this->result; + } +} diff --git a/tests/temporal/Workflow/ParallelScopesWorkflow.php b/tests/temporal/Workflow/ParallelScopesWorkflow.php new file mode 100644 index 00000000..8a2303f4 --- /dev/null +++ b/tests/temporal/Workflow/ParallelScopesWorkflow.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Promise; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; + +#[Workflow\WorkflowInterface] +class ParallelScopesWorkflow +{ + #[WorkflowMethod(name: 'ParallelScopesWorkflow')] + public function handler(string $input) + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + $a = Workflow::newCancellationScope(function () use ($simple, $input) { + return yield $simple->echo($input); + }); + + $b = Workflow::newCancellationScope(function () use ($simple, $input) { + return yield $simple->lower($input); + }); + + [$ra, $rb] = yield Promise::all([$a, $b]); + + return sprintf('%s|%s|%s', $ra, $input, $rb); + } +} diff --git a/tests/temporal/Workflow/PeriodicWorkflow.php b/tests/temporal/Workflow/PeriodicWorkflow.php new file mode 100644 index 00000000..08f5f2fa --- /dev/null +++ b/tests/temporal/Workflow/PeriodicWorkflow.php @@ -0,0 +1,19 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class PeriodicWorkflow +{ + #[WorkflowMethod(name: 'PeriodicWorkflow')] + public function handler() + { + error_log("GOT SOMETHING" . print_r(Workflow::getLastCompletionResult(), true)); + + // todo: get last completion result + return 'OK'; + } +} diff --git a/tests/temporal/Workflow/ProtoPayloadWorkflow.php b/tests/temporal/Workflow/ProtoPayloadWorkflow.php new file mode 100644 index 00000000..7adbed1e --- /dev/null +++ b/tests/temporal/Workflow/ProtoPayloadWorkflow.php @@ -0,0 +1,33 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Api\Common\V1\WorkflowExecution; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class ProtoPayloadWorkflow +{ + #[WorkflowMethod(name: 'ProtoPayloadWorkflow')] + public function handler(): iterable + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + $e = new WorkflowExecution(); + $e->setWorkflowId('workflow id'); + $e->setRunId('run id'); + + /** @var WorkflowExecution $e2 */ + $e2 = yield $simple->updateRunID($e); + assert($e2->getWorkflowId() === $e->getWorkflowId()); + assert($e2->getRunId() === 'updated'); + + return $e2; + } +} diff --git a/tests/temporal/Workflow/QueryWorkflow.php b/tests/temporal/Workflow/QueryWorkflow.php new file mode 100644 index 00000000..96e41582 --- /dev/null +++ b/tests/temporal/Workflow/QueryWorkflow.php @@ -0,0 +1,41 @@ +<?php + +/** + * This file is part of Temporal package. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Temporal\Tests\Workflow; + +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class QueryWorkflow +{ + private int $counter = 0; + + #[Workflow\SignalMethod(name: "add")] + public function add( + int $value + ) { + $this->counter += $value; + } + + #[Workflow\QueryMethod(name: "get")] + public function get(): int + { + return $this->counter; + } + + #[WorkflowMethod] + public function handler() + { + // collect signals during one second + yield Workflow::timer(1); + + return $this->counter; + } +} diff --git a/tests/temporal/Workflow/RuntimeSignalWorkflow.php b/tests/temporal/Workflow/RuntimeSignalWorkflow.php new file mode 100644 index 00000000..f700af72 --- /dev/null +++ b/tests/temporal/Workflow/RuntimeSignalWorkflow.php @@ -0,0 +1,31 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use React\Promise\Deferred; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class RuntimeSignalWorkflow +{ + #[WorkflowMethod] + public function handler() + { + $wait1 = new Deferred(); + $wait2 = new Deferred(); + + $counter = 0; + + Workflow::registerSignal('add', function ($value) use (&$counter, $wait1, $wait2) { + $counter += $value; + $wait1->resolve($value); + $wait2->resolve($value); + }); + + yield $wait1; + yield $wait2; + + return $counter; + } +} diff --git a/tests/temporal/Workflow/SagaWorkflow.php b/tests/temporal/Workflow/SagaWorkflow.php new file mode 100644 index 00000000..e47c0203 --- /dev/null +++ b/tests/temporal/Workflow/SagaWorkflow.php @@ -0,0 +1,54 @@ +<?php + +/** + * This file is part of Temporal package. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Common\RetryOptions; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Workflow; + +#[Workflow\WorkflowInterface] +class SagaWorkflow +{ + #[Workflow\WorkflowMethod(name: 'SagaWorkflow')] + public function run() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new() + ->withStartToCloseTimeout(60) + ->withRetryOptions(RetryOptions::new()->withMaximumAttempts(1)) + ); + + $saga = new Workflow\Saga(); + $saga->setParallelCompensation(true); + + try { + yield $simple->echo('test'); + $saga->addCompensation( + function () use ($simple) { + yield $simple->echo('compensate echo'); + } + ); + + yield $simple->lower('TEST'); + $saga->addCompensation( + function () use ($simple) { + yield $simple->lower('COMPENSATE LOWER'); + } + ); + + yield $simple->fail(); + } catch (\Throwable $e) { + yield $saga->compensate(); + throw $e; + } + } +} diff --git a/tests/temporal/Workflow/SideEffectWorkflow.php b/tests/temporal/Workflow/SideEffectWorkflow.php new file mode 100644 index 00000000..95d396e4 --- /dev/null +++ b/tests/temporal/Workflow/SideEffectWorkflow.php @@ -0,0 +1,30 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Common\Uuid; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; + +#[Workflow\WorkflowInterface] +class SideEffectWorkflow +{ + #[WorkflowMethod(name: 'SideEffectWorkflow')] + public function handler(string $input): iterable + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + $result = yield Workflow::sideEffect( + function () use ($input) { + return $input . '-42'; + } + ); + + return yield $simple->lower($result); + } +} diff --git a/tests/temporal/Workflow/SignalChildViaStubWorkflow.php b/tests/temporal/Workflow/SignalChildViaStubWorkflow.php new file mode 100644 index 00000000..828086fc --- /dev/null +++ b/tests/temporal/Workflow/SignalChildViaStubWorkflow.php @@ -0,0 +1,25 @@ +<?php + +namespace Temporal\Tests\Workflow; + +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class SignalChildViaStubWorkflow +{ + #[WorkflowMethod(name: 'SignalChildViaStubWorkflow')] + public function handler() + { + // typed stub + $simple = Workflow::newChildWorkflowStub(SimpleSignalledWorkflow::class); + + // start execution + $call = $simple->handler(); + + yield $simple->add(8); + + // expects 8 + return yield $call; + } +} diff --git a/tests/temporal/Workflow/SimpleDTOWorkflow.php b/tests/temporal/Workflow/SimpleDTOWorkflow.php new file mode 100644 index 00000000..bd39a0a0 --- /dev/null +++ b/tests/temporal/Workflow/SimpleDTOWorkflow.php @@ -0,0 +1,35 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; +use Temporal\Tests\DTO\Message; +use Temporal\Tests\DTO\User; + +#[Workflow\WorkflowInterface] +class SimpleDTOWorkflow +{ + #[WorkflowMethod(name: 'SimpleDTOWorkflow')]//, returnType: Message::class)] + public function handler( + User $user + ) { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new() + ->withStartToCloseTimeout(5) + ); + + $value = yield $simple->greet($user); + + if (!$value instanceof Message) { + return "FAIL"; + } + + return $value; + } +} diff --git a/tests/temporal/Workflow/SimpleHeartbeatWorkflow.php b/tests/temporal/Workflow/SimpleHeartbeatWorkflow.php new file mode 100644 index 00000000..c9999cd1 --- /dev/null +++ b/tests/temporal/Workflow/SimpleHeartbeatWorkflow.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\HeartBeatActivity; + +#[Workflow\WorkflowInterface] +class SimpleHeartbeatWorkflow +{ + #[WorkflowMethod(name: 'SimpleHeartbeatWorkflow')] + public function handler(int $iterations): iterable + { + $act = Workflow::newActivityStub( + HeartBeatActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(50) + ); + + return yield $act->doSomething($iterations); + } +} diff --git a/tests/temporal/Workflow/SimpleSignalledWorkflow.php b/tests/temporal/Workflow/SimpleSignalledWorkflow.php new file mode 100644 index 00000000..0df25a65 --- /dev/null +++ b/tests/temporal/Workflow/SimpleSignalledWorkflow.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class SimpleSignalledWorkflow +{ + private $counter = 0; + + #[Workflow\SignalMethod(name: "add")] + public function add( + int $value + ) { + $this->counter += $value; + } + + #[WorkflowMethod(name: 'SimpleSignalledWorkflow')] + public function handler(): iterable + { + // collect signals during one second + yield Workflow::timer(1); + + return $this->counter; + } +} diff --git a/tests/temporal/Workflow/SimpleSignalledWorkflowWithSleep.php b/tests/temporal/Workflow/SimpleSignalledWorkflowWithSleep.php new file mode 100644 index 00000000..d10ba04a --- /dev/null +++ b/tests/temporal/Workflow/SimpleSignalledWorkflowWithSleep.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class SimpleSignalledWorkflowWithSleep +{ + private $counter = 0; + + #[Workflow\SignalMethod(name: "add")] + public function add( + int $value + ) { + $this->counter += $value; + } + + #[WorkflowMethod(name: 'SimpleSignalledWorkflowWithSleep')] + public function handler(): iterable + { + // collect signals during one second + yield Workflow::timer(1); + + if (!Workflow::isReplaying()) { + sleep(1); + } + + return $this->counter; + } +} diff --git a/tests/temporal/Workflow/SimpleWorkflow.php b/tests/temporal/Workflow/SimpleWorkflow.php new file mode 100644 index 00000000..36e12f69 --- /dev/null +++ b/tests/temporal/Workflow/SimpleWorkflow.php @@ -0,0 +1,31 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Common\RetryOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; + +#[Workflow\WorkflowInterface] +class SimpleWorkflow +{ + #[WorkflowMethod(name: 'SimpleWorkflow')] + public function handler( + string $input + ): iterable { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new() + ->withStartToCloseTimeout(5) + ->withRetryOptions( + RetryOptions::new()->withMaximumAttempts(2) + ) + ); + + return yield $simple->echo($input); + } +} diff --git a/tests/temporal/Workflow/TimerWorkflow.php b/tests/temporal/Workflow/TimerWorkflow.php new file mode 100644 index 00000000..ab60d6c9 --- /dev/null +++ b/tests/temporal/Workflow/TimerWorkflow.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; + +#[Workflow\WorkflowInterface] +class TimerWorkflow +{ + #[WorkflowMethod(name: 'TimerWorkflow')] + public function handler(string $input): iterable + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + yield Workflow::timer(1); + + return yield $simple->lower($input); + } +} diff --git a/tests/temporal/Workflow/WaitWorkflow.php b/tests/temporal/Workflow/WaitWorkflow.php new file mode 100644 index 00000000..826952c1 --- /dev/null +++ b/tests/temporal/Workflow/WaitWorkflow.php @@ -0,0 +1,33 @@ +<?php + + +namespace Temporal\Tests\Workflow; + + +use Temporal\Workflow; +use Temporal\Workflow\SignalMethod; +use Temporal\Workflow\WorkflowInterface; +use Temporal\Workflow\WorkflowMethod; + +#[WorkflowInterface] +class WaitWorkflow +{ + private bool $ready = false; + private string $value; + + #[SignalMethod] + public function unlock( + string $value + ) { + $this->ready = true; + $this->value = $value; + } + + #[WorkflowMethod(name: 'WaitWorkflow')] + public function run() + { + yield Workflow::await(fn() => $this->ready); + + return $this->value; + } +} diff --git a/tests/temporal/Workflow/WithChildStubWorkflow.php b/tests/temporal/Workflow/WithChildStubWorkflow.php new file mode 100644 index 00000000..cdebe3d8 --- /dev/null +++ b/tests/temporal/Workflow/WithChildStubWorkflow.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class WithChildStubWorkflow +{ + #[WorkflowMethod(name: 'WithChildStubWorkflow')] + public function handler(string $input): iterable + { + $child = Workflow::newChildWorkflowStub(SimpleWorkflow::class); + + return 'Child: ' . (yield $child->handler('child ' . $input)); + } +} diff --git a/tests/temporal/Workflow/WithChildWorkflow.php b/tests/temporal/Workflow/WithChildWorkflow.php new file mode 100644 index 00000000..aac0979b --- /dev/null +++ b/tests/temporal/Workflow/WithChildWorkflow.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace Temporal\Tests\Workflow; + +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; + +#[Workflow\WorkflowInterface] +class WithChildWorkflow +{ + #[WorkflowMethod(name: 'WithChildWorkflow')] + public function handler( + string $input + ): iterable { + $result = yield Workflow::executeChildWorkflow( + 'SimpleWorkflow', + ['child ' . $input], + Workflow\ChildWorkflowOptions::new() + ); + + return 'Child: ' . $result; + } +} diff --git a/tests/temporal/Workflow/WorkflowWithSequence.php b/tests/temporal/Workflow/WorkflowWithSequence.php new file mode 100644 index 00000000..9e813a9c --- /dev/null +++ b/tests/temporal/Workflow/WorkflowWithSequence.php @@ -0,0 +1,30 @@ +<?php + + +namespace Temporal\Tests\Workflow; + +use Temporal\Activity\ActivityOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; + +#[Workflow\WorkflowInterface] +class WorkflowWithSequence +{ + #[WorkflowMethod(name: 'WorkflowWithSequence')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + $a = $simple->echo('a'); + $b = $simple->echo('b'); + + yield $a; + yield $b; + + return 'OK'; + } +} diff --git a/tests/temporal/Workflow/WorkflowWithSignalledSteps.php b/tests/temporal/Workflow/WorkflowWithSignalledSteps.php new file mode 100644 index 00000000..5f1af766 --- /dev/null +++ b/tests/temporal/Workflow/WorkflowWithSignalledSteps.php @@ -0,0 +1,51 @@ +<?php + + +namespace Temporal\Tests\Workflow; + +use React\Promise\Deferred; +use React\Promise\PromiseInterface; +use Temporal\Activity\ActivityOptions; +use Temporal\Workflow; +use Temporal\Workflow\WorkflowMethod; +use Temporal\Tests\Activity\SimpleActivity; + +#[Workflow\WorkflowInterface] +class WorkflowWithSignalledSteps +{ + #[WorkflowMethod(name: 'WorkflowWithSignalledSteps')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + $value = 0; + Workflow::registerQuery('value', function () use (&$value) { + return $value; + }); + + yield $this->promiseSignal('begin'); + $value++; + + yield $this->promiseSignal('next1'); + $value++; + + yield $this->promiseSignal('next2'); + $value++; + + return $value; + } + + // is this correct? + private function promiseSignal(string $name): PromiseInterface + { + $signal = new Deferred(); + Workflow::registerSignal($name, function ($value) use ($signal) { + $signal->resolve($value); + }); + + return $signal->promise(); + } +} |