From 92bd6c3b3c6d6649cb3b0c445f2bb28ddcd8dced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C4=81niels=20Stu=C4=A3is?= Date: Fri, 11 Apr 2025 17:16:40 +0300 Subject: [PATCH 1/4] fix: incorrect updateWithStart signature --- .../WorkflowClientCallsInterceptorTrait.php | 2 +- .../WorkflowClientCallsInterceptor.php | 4 +- .../Interceptor/InterceptorCallsCounter.php | 13 ++++++ .../Interceptor/UpdateHeadersWorkflow.php | 44 +++++++++++++++++++ .../Interceptor/InterceptorsTestCase.php | 27 ++++++++++++ 5 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 tests/Fixtures/src/Workflow/Interceptor/UpdateHeadersWorkflow.php diff --git a/src/Interceptor/Trait/WorkflowClientCallsInterceptorTrait.php b/src/Interceptor/Trait/WorkflowClientCallsInterceptorTrait.php index 5c07fb26a..eb0f6a2c3 100644 --- a/src/Interceptor/Trait/WorkflowClientCallsInterceptorTrait.php +++ b/src/Interceptor/Trait/WorkflowClientCallsInterceptorTrait.php @@ -80,7 +80,7 @@ public function signalWithStart(SignalWithStartInput $input, callable $next): Wo * * @see WorkflowClientCallsInterceptor::updateWithStart() */ - public function updateWithStart(UpdateWithStartInput $input, callable $next): UpdateHandle + public function updateWithStart(UpdateWithStartInput $input, callable $next): array { return $next($input); } diff --git a/src/Interceptor/WorkflowClientCallsInterceptor.php b/src/Interceptor/WorkflowClientCallsInterceptor.php index c69424dc5..25f203c22 100644 --- a/src/Interceptor/WorkflowClientCallsInterceptor.php +++ b/src/Interceptor/WorkflowClientCallsInterceptor.php @@ -75,9 +75,9 @@ public function signalWithStart(SignalWithStartInput $input, callable $next): Wo * @param UpdateWithStartInput $input * @param callable(UpdateWithStartInput): WorkflowExecution $next * - * @return UpdateHandle + * @return array{WorkflowExecution, UpdateHandle|\Throwable} */ - public function updateWithStart(UpdateWithStartInput $input, callable $next): UpdateHandle; + public function updateWithStart(UpdateWithStartInput $input, callable $next): array; /** * @param callable(GetResultInput): ?ValuesInterface $next diff --git a/tests/Fixtures/src/Interceptor/InterceptorCallsCounter.php b/tests/Fixtures/src/Interceptor/InterceptorCallsCounter.php index e51f2498b..9e3b09408 100644 --- a/tests/Fixtures/src/Interceptor/InterceptorCallsCounter.php +++ b/tests/Fixtures/src/Interceptor/InterceptorCallsCounter.php @@ -21,8 +21,10 @@ use Temporal\Interceptor\Trait\WorkflowOutboundRequestInterceptorTrait; use Temporal\Interceptor\WorkflowClient\SignalWithStartInput; use Temporal\Interceptor\WorkflowClient\StartInput; +use Temporal\Interceptor\WorkflowClient\UpdateWithStartInput; use Temporal\Interceptor\WorkflowClientCallsInterceptor; use Temporal\Interceptor\WorkflowInbound\SignalInput; +use Temporal\Interceptor\WorkflowInbound\UpdateInput; use Temporal\Interceptor\WorkflowInbound\WorkflowInput; use Temporal\Interceptor\WorkflowInboundCallsInterceptor; use Temporal\Interceptor\WorkflowOutboundRequestInterceptor; @@ -92,4 +94,15 @@ public function signalWithStart(SignalWithStartInput $input, callable $next): Wo ), ); } + + public function updateWithStart(UpdateWithStartInput $input, callable $next): array + { + return $next( + $input->with( + workflowStartInput: $input->workflowStartInput->with( + header: $this->increment($input->workflowStartInput->header, __FUNCTION__), + ), + ), + ); + } } diff --git a/tests/Fixtures/src/Workflow/Interceptor/UpdateHeadersWorkflow.php b/tests/Fixtures/src/Workflow/Interceptor/UpdateHeadersWorkflow.php new file mode 100644 index 000000000..de454dcb0 --- /dev/null +++ b/tests/Fixtures/src/Workflow/Interceptor/UpdateHeadersWorkflow.php @@ -0,0 +1,44 @@ + $this->updated); + + $this->headers = \iterator_to_array(Workflow::getCurrentContext()->getHeader()); + + return $this->headers; + } + + #[Workflow\UpdateMethod] + public function update(): void + { + $this->updated = true; + } + + #[Workflow\QueryMethod] + public function headers(): mixed + { + return $this->headers; + } +} diff --git a/tests/Functional/Interceptor/InterceptorsTestCase.php b/tests/Functional/Interceptor/InterceptorsTestCase.php index b41db0a9c..20ebc614f 100644 --- a/tests/Functional/Interceptor/InterceptorsTestCase.php +++ b/tests/Functional/Interceptor/InterceptorsTestCase.php @@ -12,11 +12,14 @@ namespace Temporal\Tests\Functional\Interceptor; use Carbon\CarbonInterval; +use Temporal\Client\Update\LifecycleStage; +use Temporal\Client\Update\UpdateOptions; use Temporal\Client\WorkflowOptions; use Temporal\Testing\WithoutTimeSkipping; use Temporal\Tests\Workflow\Interceptor\HeadersWorkflow; use Temporal\Tests\Workflow\Interceptor\QueryHeadersWorkflow; use Temporal\Tests\Workflow\Interceptor\SignalHeadersWorkflow; +use Temporal\Tests\Workflow\Interceptor\UpdateHeadersWorkflow; /** * @group client @@ -111,6 +114,30 @@ public function testSignalWithStartMethod(): void ], (array)$run->getResult()); } + public function testUpdateWithStartMethod(): void + { + $client = $this->createClient(); + $workflow = $client->newWorkflowStub( + UpdateHeadersWorkflow::class, + WorkflowOptions::new() + ->withWorkflowExecutionTimeout(CarbonInterval::seconds(5)), + ); + + $run = $client->updateWithStart($workflow, 'update'); + + // Workflow header + $this->assertEquals([ + /** @see \Temporal\Tests\Interceptor\InterceptorCallsCounter::updateWithStart() */ + 'updateWithStart' => '1', + /** + * Inherited from handler run + * + * @see \Temporal\Tests\Interceptor\InterceptorCallsCounter::execute() + */ + 'execute' => '1', + ], $workflow->headers()); + } + // todo: rewrite tests because there is no header in query call // todo: add test about dynamic query // public function testQueryMethod(): void From 2bbb22f4599e8525edb7b01aa38e8c70e4e12a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C4=81niels=20Stu=C4=A3is?= Date: Tue, 15 Apr 2025 18:34:45 +0300 Subject: [PATCH 2/4] add UpdateWithStartOutput DTO --- src/Client/WorkflowClient.php | 8 ++-- .../WorkflowClientCallsInterceptorTrait.php | 4 +- .../WorkflowClient/UpdateWithStartOutput.php | 37 +++++++++++++++++++ .../WorkflowClientCallsInterceptor.php | 6 +-- src/Internal/Client/WorkflowStarter.php | 34 +++++++++-------- .../Interceptor/InterceptorCallsCounter.php | 3 +- tests/Functional/.rr.silent.yaml | 2 +- .../Interceptor/InterceptorsTestCase.php | 2 +- 8 files changed, 66 insertions(+), 30 deletions(-) create mode 100644 src/Interceptor/WorkflowClient/UpdateWithStartOutput.php diff --git a/src/Client/WorkflowClient.php b/src/Client/WorkflowClient.php index 23985c099..774d11279 100644 --- a/src/Client/WorkflowClient.php +++ b/src/Client/WorkflowClient.php @@ -250,7 +250,7 @@ public function updateWithStart( ); $workflowStub->hasExecution() and throw new InvalidArgumentException(self::ERROR_WORKFLOW_START_DUPLICATION); - [$execution, $handle] = $this->getStarter()->updateWithStart( + $output = $this->getStarter()->updateWithStart( $workflowType, $workflowStub->getOptions() ?? WorkflowOptions::new(), $update, @@ -258,11 +258,9 @@ public function updateWithStart( $startArgs, ); - $workflowStub->setExecution($execution); + $workflowStub->setExecution($output->getExecution()); - return $handle instanceof \Throwable - ? throw $handle - : $handle; + return $output->getHandle(); } /** diff --git a/src/Interceptor/Trait/WorkflowClientCallsInterceptorTrait.php b/src/Interceptor/Trait/WorkflowClientCallsInterceptorTrait.php index eb0f6a2c3..3800ab132 100644 --- a/src/Interceptor/Trait/WorkflowClientCallsInterceptorTrait.php +++ b/src/Interceptor/Trait/WorkflowClientCallsInterceptorTrait.php @@ -11,7 +11,6 @@ namespace Temporal\Interceptor\Trait; -use Temporal\Client\Update\UpdateHandle; use Temporal\Client\Workflow\WorkflowExecutionDescription; use Temporal\DataConverter\EncodedValues; use Temporal\Interceptor\WorkflowClient\CancelInput; @@ -25,6 +24,7 @@ use Temporal\Interceptor\WorkflowClient\TerminateInput; use Temporal\Interceptor\WorkflowClient\UpdateInput; use Temporal\Interceptor\WorkflowClient\UpdateWithStartInput; +use Temporal\Interceptor\WorkflowClient\UpdateWithStartOutput; use Temporal\Interceptor\WorkflowClientCallsInterceptor; use Temporal\Workflow\WorkflowExecution; @@ -80,7 +80,7 @@ public function signalWithStart(SignalWithStartInput $input, callable $next): Wo * * @see WorkflowClientCallsInterceptor::updateWithStart() */ - public function updateWithStart(UpdateWithStartInput $input, callable $next): array + public function updateWithStart(UpdateWithStartInput $input, callable $next): UpdateWithStartOutput { return $next($input); } diff --git a/src/Interceptor/WorkflowClient/UpdateWithStartOutput.php b/src/Interceptor/WorkflowClient/UpdateWithStartOutput.php new file mode 100644 index 000000000..878e1f786 --- /dev/null +++ b/src/Interceptor/WorkflowClient/UpdateWithStartOutput.php @@ -0,0 +1,37 @@ +execution; + } + + public function getHandle(): UpdateHandle + { + if ($this->handle instanceof \Throwable) { + throw $this->handle; + } + + return $this->handle; + } +} diff --git a/src/Interceptor/WorkflowClientCallsInterceptor.php b/src/Interceptor/WorkflowClientCallsInterceptor.php index 25f203c22..d9745adcf 100644 --- a/src/Interceptor/WorkflowClientCallsInterceptor.php +++ b/src/Interceptor/WorkflowClientCallsInterceptor.php @@ -11,7 +11,6 @@ namespace Temporal\Interceptor; -use Temporal\Client\Update\UpdateHandle; use Temporal\Client\Workflow\WorkflowExecutionDescription; use Temporal\DataConverter\ValuesInterface; use Temporal\Interceptor\Trait\WorkflowClientCallsInterceptorTrait; @@ -26,6 +25,7 @@ use Temporal\Interceptor\WorkflowClient\TerminateInput; use Temporal\Interceptor\WorkflowClient\UpdateInput; use Temporal\Interceptor\WorkflowClient\UpdateWithStartInput; +use Temporal\Interceptor\WorkflowClient\UpdateWithStartOutput; use Temporal\Internal\Interceptor\Interceptor; use Temporal\Workflow\WorkflowExecution; @@ -74,10 +74,8 @@ public function signalWithStart(SignalWithStartInput $input, callable $next): Wo /** * @param UpdateWithStartInput $input * @param callable(UpdateWithStartInput): WorkflowExecution $next - * - * @return array{WorkflowExecution, UpdateHandle|\Throwable} */ - public function updateWithStart(UpdateWithStartInput $input, callable $next): array; + public function updateWithStart(UpdateWithStartInput $input, callable $next): UpdateWithStartOutput; /** * @param callable(GetResultInput): ?ValuesInterface $next diff --git a/src/Internal/Client/WorkflowStarter.php b/src/Internal/Client/WorkflowStarter.php index 592b58f43..ace136aef 100644 --- a/src/Internal/Client/WorkflowStarter.php +++ b/src/Internal/Client/WorkflowStarter.php @@ -41,6 +41,7 @@ use Temporal\Interceptor\WorkflowClient\StartInput; use Temporal\Interceptor\WorkflowClient\UpdateInput; use Temporal\Interceptor\WorkflowClient\UpdateWithStartInput; +use Temporal\Interceptor\WorkflowClient\UpdateWithStartOutput; use Temporal\Interceptor\WorkflowClientCallsInterceptor; use Temporal\Internal\Interceptor\Pipeline; use Temporal\Internal\Support\DateInterval; @@ -128,8 +129,6 @@ function (SignalWithStartInput $input): WorkflowExecution { /** * @param non-empty-string $workflowType - * - * @return array{WorkflowExecution, UpdateHandle|\Throwable} */ public function updateWithStart( string $workflowType, @@ -137,12 +136,12 @@ public function updateWithStart( UpdateOptions $update, array $updateArgs = [], array $startArgs = [], - ): array { + ): UpdateWithStartOutput { $arguments = EncodedValues::fromValues($startArgs, $this->converter); $updateArguments = EncodedValues::fromValues($updateArgs, $this->converter); return $this->interceptors->with( - function (UpdateWithStartInput $input): array { + function (UpdateWithStartInput $input): UpdateWithStartOutput { $startRequest = $this->configureExecutionRequest( new StartWorkflowExecutionRequest(), $input->workflowStartInput, @@ -234,20 +233,23 @@ function (UpdateWithStartInput $input): array { workflowExecution: $execution, ); } catch (\RuntimeException $e) { - return [$execution, $e]; + return new UpdateWithStartOutput($execution, $e); } - return [$execution, new UpdateHandle( - client: $this->serviceClient, - clientOptions: $this->clientOptions, - converter: $this->converter, - execution: $updateResult->getReference()->workflowExecution, - workflowType: $input->updateInput->workflowType, - updateName: $input->updateInput->updateName, - resultType: $input->updateInput->resultType, - updateId: $updateResult->getReference()->updateId, - result: $updateResult->getResult(), - )]; + return new UpdateWithStartOutput( + $execution, + new UpdateHandle( + client: $this->serviceClient, + clientOptions: $this->clientOptions, + converter: $this->converter, + execution: $updateResult->getReference()->workflowExecution, + workflowType: $input->updateInput->workflowType, + updateName: $input->updateInput->updateName, + resultType: $input->updateInput->resultType, + updateId: $updateResult->getReference()->updateId, + result: $updateResult->getResult(), + ), + ); }, /** @see WorkflowClientCallsInterceptor::updateWithStart() */ 'updateWithStart', diff --git a/tests/Fixtures/src/Interceptor/InterceptorCallsCounter.php b/tests/Fixtures/src/Interceptor/InterceptorCallsCounter.php index 9e3b09408..78d4cd199 100644 --- a/tests/Fixtures/src/Interceptor/InterceptorCallsCounter.php +++ b/tests/Fixtures/src/Interceptor/InterceptorCallsCounter.php @@ -22,6 +22,7 @@ use Temporal\Interceptor\WorkflowClient\SignalWithStartInput; use Temporal\Interceptor\WorkflowClient\StartInput; use Temporal\Interceptor\WorkflowClient\UpdateWithStartInput; +use Temporal\Interceptor\WorkflowClient\UpdateWithStartOutput; use Temporal\Interceptor\WorkflowClientCallsInterceptor; use Temporal\Interceptor\WorkflowInbound\SignalInput; use Temporal\Interceptor\WorkflowInbound\UpdateInput; @@ -95,7 +96,7 @@ public function signalWithStart(SignalWithStartInput $input, callable $next): Wo ); } - public function updateWithStart(UpdateWithStartInput $input, callable $next): array + public function updateWithStart(UpdateWithStartInput $input, callable $next): UpdateWithStartOutput { return $next( $input->with( diff --git a/tests/Functional/.rr.silent.yaml b/tests/Functional/.rr.silent.yaml index 7ec8f4a6d..d1e2484c7 100644 --- a/tests/Functional/.rr.silent.yaml +++ b/tests/Functional/.rr.silent.yaml @@ -4,7 +4,7 @@ rpc: listen: tcp://127.0.0.1:6001 server: - command: "php worker.php" + command: "php -derror_reporting=0 worker.php" env: XDEBUG_SESSION: 1 diff --git a/tests/Functional/Interceptor/InterceptorsTestCase.php b/tests/Functional/Interceptor/InterceptorsTestCase.php index 20ebc614f..ced3d0bbf 100644 --- a/tests/Functional/Interceptor/InterceptorsTestCase.php +++ b/tests/Functional/Interceptor/InterceptorsTestCase.php @@ -135,7 +135,7 @@ public function testUpdateWithStartMethod(): void * @see \Temporal\Tests\Interceptor\InterceptorCallsCounter::execute() */ 'execute' => '1', - ], $workflow->headers()); + ], (array) $workflow->headers()); } // todo: rewrite tests because there is no header in query call From 993dd5fcf302c69ae711f715bb7b78f0b80200bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C4=81niels=20Stu=C4=A3is?= Date: Wed, 16 Apr 2025 08:47:27 +0300 Subject: [PATCH 3/4] revert rr config --- tests/Functional/.rr.silent.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Functional/.rr.silent.yaml b/tests/Functional/.rr.silent.yaml index d1e2484c7..7ec8f4a6d 100644 --- a/tests/Functional/.rr.silent.yaml +++ b/tests/Functional/.rr.silent.yaml @@ -4,7 +4,7 @@ rpc: listen: tcp://127.0.0.1:6001 server: - command: "php -derror_reporting=0 worker.php" + command: "php worker.php" env: XDEBUG_SESSION: 1 From 9e7cbe7ca469e843b7ba4aa39c3af268795a8ff6 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Thu, 1 May 2025 18:15:14 +0400 Subject: [PATCH 4/4] Replace getters with public properties --- src/Client/WorkflowClient.php | 6 ++++-- .../WorkflowClient/UpdateWithStartOutput.php | 18 ++---------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/Client/WorkflowClient.php b/src/Client/WorkflowClient.php index 774d11279..68cf557b0 100644 --- a/src/Client/WorkflowClient.php +++ b/src/Client/WorkflowClient.php @@ -258,9 +258,11 @@ public function updateWithStart( $startArgs, ); - $workflowStub->setExecution($output->getExecution()); + $workflowStub->setExecution($output->execution); - return $output->getHandle(); + return $output->handle instanceof UpdateHandle + ? $output->handle + : throw $output->handle; } /** diff --git a/src/Interceptor/WorkflowClient/UpdateWithStartOutput.php b/src/Interceptor/WorkflowClient/UpdateWithStartOutput.php index 878e1f786..83a81c306 100644 --- a/src/Interceptor/WorkflowClient/UpdateWithStartOutput.php +++ b/src/Interceptor/WorkflowClient/UpdateWithStartOutput.php @@ -17,21 +17,7 @@ final class UpdateWithStartOutput { public function __construct( - private readonly WorkflowExecution $execution, - private readonly UpdateHandle|\Throwable $handle, + public readonly WorkflowExecution $execution, + public readonly UpdateHandle|\Throwable $handle, ) {} - - public function getExecution(): WorkflowExecution - { - return $this->execution; - } - - public function getHandle(): UpdateHandle - { - if ($this->handle instanceof \Throwable) { - throw $this->handle; - } - - return $this->handle; - } }