From d20614cf12d860a081c6aa228d3de743f705d4d7 Mon Sep 17 00:00:00 2001 From: Aleksei Gagarin Date: Thu, 23 Nov 2023 12:13:26 +0400 Subject: [PATCH] Expose Workflow Start Delay (#374) --- composer.json | 2 +- src/Client/WorkflowOptions.php | 31 ++++++++++++++++++++++ src/Internal/Client/WorkflowStarter.php | 1 + tests/Unit/DTO/WorkflowOptionsTestCase.php | 10 +++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5686950a..bff0190b 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "psr/log": "^2.0 || ^3.0", "ramsey/uuid": "^4.7", "react/promise": "^2.9", - "roadrunner-php/roadrunner-api-dto": "^1.3", + "roadrunner-php/roadrunner-api-dto": "^1.4", "roadrunner-php/version-checker": "^1.0", "spiral/attributes": "^2.8 || ^3.0", "spiral/roadrunner": "^v2023.2", diff --git a/src/Client/WorkflowOptions.php b/src/Client/WorkflowOptions.php index 33d9f618..38d2a4e4 100644 --- a/src/Client/WorkflowOptions.php +++ b/src/Client/WorkflowOptions.php @@ -84,6 +84,12 @@ final class WorkflowOptions extends Options #[Marshal(name: 'WorkflowRunTimeout', type: DateIntervalType::class)] public \DateInterval $workflowRunTimeout; + /** + * Time to wait before dispatching the first Workflow task. + */ + #[Marshal(name: 'WorkflowStartDelay', type: DateIntervalType::class)] + public \DateInterval $workflowStartDelay; + /** * The timeout for processing workflow task from the time the worker pulled * this task. If a workflow task is lost, it is retried after this timeout. @@ -146,6 +152,7 @@ public function __construct() $this->workflowExecutionTimeout = CarbonInterval::seconds(0); $this->workflowRunTimeout = CarbonInterval::seconds(0); $this->workflowTaskTimeout = CarbonInterval::seconds(0); + $this->workflowStartDelay = CarbonInterval::seconds(0); parent::__construct(); } @@ -293,6 +300,30 @@ public function withWorkflowTaskTimeout($timeout): self return $self; } + /** + * Time to wait before dispatching the first Workflow task. + * If the Workflow gets a Signal before the delay, a Workflow task will be dispatched and the rest + * of the delay will be ignored. A Signal from {@see WorkflowClientInterface::startWithSignal()} won't + * trigger a workflow task. Cannot be set the same time as a {@see $cronSchedule}. + * + * NOTE: Experimental + * + * @psalm-suppress ImpureMethodCall + * + * @param DateIntervalValue $delay + * @return $this + */ + #[Pure] + public function withWorkflowStartDelay($delay): self + { + assert(DateInterval::assert($delay)); + $delay = DateInterval::parse($delay, DateInterval::FORMAT_SECONDS); + + $self = clone $this; + $self->workflowStartDelay = $delay; + return $self; + } + /** * Specifies server behavior if a completed workflow with the same id * exists. Note that under no conditions Temporal allows two workflows diff --git a/src/Internal/Client/WorkflowStarter.php b/src/Internal/Client/WorkflowStarter.php index 016500a2..a5da4a58 100644 --- a/src/Internal/Client/WorkflowStarter.php +++ b/src/Internal/Client/WorkflowStarter.php @@ -191,6 +191,7 @@ private function configureExecutionRequest( ->setTaskQueue(new TaskQueue(['name' => $options->taskQueue])) ->setWorkflowType(new WorkflowType(['name' => $input->workflowType])) ->setWorkflowId($input->workflowId) + ->setWorkflowStartDelay(DateInterval::toDuration($options->workflowStartDelay)) ->setCronSchedule($options->cronSchedule ?? '') ->setRetryPolicy($options->retryOptions ? $options->retryOptions->toWorkflowRetryPolicy() : null) ->setWorkflowIdReusePolicy($options->workflowIdReusePolicy) diff --git a/tests/Unit/DTO/WorkflowOptionsTestCase.php b/tests/Unit/DTO/WorkflowOptionsTestCase.php index cf0fce98..2f04ca90 100644 --- a/tests/Unit/DTO/WorkflowOptionsTestCase.php +++ b/tests/Unit/DTO/WorkflowOptionsTestCase.php @@ -35,6 +35,7 @@ public function testMarshalling(): void 'EnableEagerStart' => false, 'WorkflowExecutionTimeout' => 0, 'WorkflowRunTimeout' => 0, + 'WorkflowStartDelay' => 0, 'WorkflowTaskTimeout' => 0, 'WorkflowIDReusePolicy' => 2, 'RetryPolicy' => null, @@ -96,6 +97,15 @@ public function testWorkflowTaskTimeoutChangesNotMutateState(): void )); } + public function testWorkflowStartDelayChangesNotMutateState(): void + { + $dto = new WorkflowOptions(); + + $this->assertNotSame($dto, $dto->withWorkflowStartDelay( + CarbonInterval::seconds(10) + )); + } + public function testWorkflowIdReusePolicyChangesNotMutateState(): void { $dto = new WorkflowOptions();