From 48ff1908f03d30c435ed2a85e9459adbe8b2dbd9 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Mon, 19 Aug 2024 23:16:10 +0400 Subject: [PATCH] Add WorkflowUpdateRPCTimeoutOrCanceledException; add a test case --- src/Client/Update/UpdateHandle.php | 20 +++-- src/Client/WorkflowStubInterface.php | 6 +- src/Exception/Client/TimeoutException.php | 7 +- .../Client/WorkflowUpdateException.php | 2 +- ...lowUpdateRPCTimeoutOrCanceledException.php | 29 +++++++ src/Internal/Client/WorkflowStub.php | 3 + tests/Acceptance/App/Attribute/Client.php | 2 +- tests/Acceptance/Extra/Update/TimeoutTest.php | 75 +++++++++++++++++++ 8 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 src/Exception/Client/WorkflowUpdateRPCTimeoutOrCanceledException.php create mode 100644 tests/Acceptance/Extra/Update/TimeoutTest.php diff --git a/src/Client/Update/UpdateHandle.php b/src/Client/Update/UpdateHandle.php index 4ee309636..42bbc71ba 100644 --- a/src/Client/Update/UpdateHandle.php +++ b/src/Client/Update/UpdateHandle.php @@ -12,6 +12,7 @@ use Temporal\DataConverter\ValuesInterface; use Temporal\Exception\Client\TimeoutException; use Temporal\Exception\Client\WorkflowUpdateException; +use Temporal\Exception\Client\WorkflowUpdateRPCTimeoutOrCanceledException; use Temporal\Exception\Failure\FailureConverter; use Temporal\Workflow\WorkflowExecution; @@ -70,7 +71,7 @@ public function hasResult(): bool * @param int|float|null $timeout Timeout in seconds. Accuracy to milliseconds. * * @throws WorkflowUpdateException - * @throws TimeoutException + * @throws WorkflowUpdateRPCTimeoutOrCanceledException */ public function getResult(int|float|null $timeout = null): mixed { @@ -83,7 +84,7 @@ public function getResult(int|float|null $timeout = null): mixed * @param int|float|null $timeout Timeout in seconds. Accuracy to milliseconds. * * @throws WorkflowUpdateException - * @throws TimeoutException + * @throws WorkflowUpdateRPCTimeoutOrCanceledException */ public function getEncodedValues(int|float|null $timeout = null): ValuesInterface { @@ -100,7 +101,7 @@ public function getEncodedValues(int|float|null $timeout = null): ValuesInterfac * @param int|float|null $timeout Timeout in seconds. Accuracy to milliseconds. * * @psalm-assert !null $this->result - * @throws TimeoutException + * @throws WorkflowUpdateRPCTimeoutOrCanceledException */ private function fetchResult(int|float|null $timeout = null): void { @@ -116,10 +117,14 @@ private function fetchResult(int|float|null $timeout = null): void (new \Temporal\Api\Update\V1\WaitPolicy())->setLifecycleStage(LifecycleStage::StageCompleted->value) ); - $response = $this->client->PollWorkflowExecutionUpdate( - $request, - $timeout === null ? null : $this->client->getContext()->withTimeout($timeout), - ); + try { + $response = $this->client->PollWorkflowExecutionUpdate( + $request, + $timeout === null ? null : $this->client->getContext()->withTimeout($timeout), + ); + } catch (TimeoutException $e) { + throw WorkflowUpdateRPCTimeoutOrCanceledException::fromTimeoutException($e); + } // Workflow Uprate accepted $result = $response->getOutcome(); @@ -135,6 +140,7 @@ private function fetchResult(int|float|null $timeout = null): void $failure = $result->getFailure(); \assert($failure !== null); $e = FailureConverter::mapFailureToException($failure, $this->converter); + tr($e); $this->result = new WorkflowUpdateException( $e->getMessage(), diff --git a/src/Client/WorkflowStubInterface.php b/src/Client/WorkflowStubInterface.php index 2e25c8dfd..f49b1a86b 100644 --- a/src/Client/WorkflowStubInterface.php +++ b/src/Client/WorkflowStubInterface.php @@ -15,6 +15,8 @@ use Temporal\Client\Update\UpdateOptions; use Temporal\DataConverter\Type; use Temporal\DataConverter\ValuesInterface; +use Temporal\Exception\Client\WorkflowUpdateException; +use Temporal\Exception\Client\WorkflowUpdateRPCTimeoutOrCanceledException; use Temporal\Exception\IllegalStateException; use Temporal\Workflow\CancellationScopeInterface; use Temporal\Workflow\QueryMethod; @@ -91,6 +93,8 @@ public function query(string $name, ...$args): ?ValuesInterface; * @param non-empty-string $name Name of the update handler. * @param mixed ...$args Arguments to pass to the update handler. * @return ValuesInterface|null + * @throws WorkflowUpdateException + * @throws WorkflowUpdateRPCTimeoutOrCanceledException */ public function update(string $name, ...$args): ?ValuesInterface; @@ -107,7 +111,7 @@ public function update(string $name, ...$args): ?ValuesInterface; * * @param non-empty-string|UpdateOptions $nameOrOptions Name of the update handler or update options. * @param mixed ...$args Arguments to pass to the update handler. - * @return UpdateHandle + * @throws WorkflowUpdateRPCTimeoutOrCanceledException */ public function startUpdate(string|UpdateOptions $nameOrOptions, ...$args): UpdateHandle; diff --git a/src/Exception/Client/TimeoutException.php b/src/Exception/Client/TimeoutException.php index 93f135a48..52fcfae95 100644 --- a/src/Exception/Client/TimeoutException.php +++ b/src/Exception/Client/TimeoutException.php @@ -13,6 +13,7 @@ use Temporal\Exception\TemporalException; -class TimeoutException extends TemporalException -{ -} +/** + * RPC timeout or cancellation. + */ +class TimeoutException extends TemporalException {} diff --git a/src/Exception/Client/WorkflowUpdateException.php b/src/Exception/Client/WorkflowUpdateException.php index c68826c3f..f18d14cdc 100644 --- a/src/Exception/Client/WorkflowUpdateException.php +++ b/src/Exception/Client/WorkflowUpdateException.php @@ -13,7 +13,7 @@ use Temporal\Workflow\WorkflowExecution; -final class WorkflowUpdateException extends WorkflowException +class WorkflowUpdateException extends WorkflowException { public function __construct( ?string $message, diff --git a/src/Exception/Client/WorkflowUpdateRPCTimeoutOrCanceledException.php b/src/Exception/Client/WorkflowUpdateRPCTimeoutOrCanceledException.php new file mode 100644 index 000000000..a0e147dc8 --- /dev/null +++ b/src/Exception/Client/WorkflowUpdateRPCTimeoutOrCanceledException.php @@ -0,0 +1,29 @@ +getMessage(), + $exception->getCode(), + $exception->getPrevious(), + ); + } +} diff --git a/src/Internal/Client/WorkflowStub.php b/src/Internal/Client/WorkflowStub.php index e634aad8e..387a8a455 100644 --- a/src/Internal/Client/WorkflowStub.php +++ b/src/Internal/Client/WorkflowStub.php @@ -51,6 +51,7 @@ use Temporal\Exception\Client\WorkflowQueryRejectedException; use Temporal\Exception\Client\WorkflowServiceException; use Temporal\Exception\Client\WorkflowUpdateException; +use Temporal\Exception\Client\WorkflowUpdateRPCTimeoutOrCanceledException; use Temporal\Exception\Failure\CanceledFailure; use Temporal\Exception\Failure\FailureConverter; use Temporal\Exception\Failure\TerminatedFailure; @@ -332,6 +333,8 @@ static function ( } throw WorkflowServiceException::withoutMessage($input->workflowExecution, $input->workflowType, $e); + } catch (TimeoutException $e) { + throw WorkflowUpdateRPCTimeoutOrCanceledException::fromTimeoutException($e); } catch (\Throwable $e) { throw new WorkflowServiceException(null, $input->workflowExecution, $input->workflowType, $e); } diff --git a/tests/Acceptance/App/Attribute/Client.php b/tests/Acceptance/App/Attribute/Client.php index 211004575..d2334b2dd 100644 --- a/tests/Acceptance/App/Attribute/Client.php +++ b/tests/Acceptance/App/Attribute/Client.php @@ -13,7 +13,7 @@ final class Client { public function __construct( - public int|string|null $timeout = null, + public float|null $timeout = null, public \Closure|array|string|null $pipelineProvider = null, public array $payloadConverters = [], ) { diff --git a/tests/Acceptance/Extra/Update/TimeoutTest.php b/tests/Acceptance/Extra/Update/TimeoutTest.php new file mode 100644 index 000000000..57a01d16e --- /dev/null +++ b/tests/Acceptance/Extra/Update/TimeoutTest.php @@ -0,0 +1,75 @@ +startUpdate('sleep', '1 second'); + + $this->expectException(WorkflowUpdateRPCTimeoutOrCanceledException::class); + + $handle->getResult(0.2); + } + + #[Test] + public function doUpdateWithTimeout( + #[Stub('Extra_Timeout_WorkflowUpdate')] + #[Client(timeout: 1.2)] + WorkflowStubInterface $stub, + ): void { + $this->expectException(WorkflowUpdateRPCTimeoutOrCanceledException::class); + + /** @see TestWorkflow::sleep */ + $stub->update('sleep', '2 second'); + } + + #[Test] + public function withoutRunningWorker(WorkflowClientInterface $client): void + { + $client = $client->withTimeout(1.2); + $wf = $client->newUntypedWorkflowStub('Extra_Timeout_WorkflowUpdate', WorkflowOptions::new() + ->withTaskQueue('not-existing-task-queue')); + $client->start($wf); + + $this->expectException(WorkflowUpdateRPCTimeoutOrCanceledException::class); + + /** @see TestWorkflow::sleep */ + $wf->update('sleep', '2 second'); + } +} + +#[WorkflowInterface] +class TestWorkflow +{ + #[WorkflowMethod(name: "Extra_Timeout_WorkflowUpdate")] + public function handle() + { + yield Workflow::await(static fn() => false); + } + + #[Workflow\UpdateMethod(name: 'sleep')] + public function sleep(string $sleep): mixed + { + yield Workflow::timer(\DateInterval::createFromDateString($sleep)); + } +}