From a22cbf534e0bd82af1646a6fdffddb5febe3e1d5 Mon Sep 17 00:00:00 2001 From: Dmitriy Derepko Date: Tue, 11 Aug 2026 13:04:46 +0400 Subject: [PATCH] feat: make eager activity reservation limit configurable Add WorkerOptions::$maxEagerActivityReservationsPerWorkflowTask (marshalled as MaxEagerActivityReservationsPerWorkflowTask) exposing sdk-go's per-workflow-task eager-activity reservation cap. Nullable: unset marshals to null so the Go worker.Options *int stays nil and falls back to the default of 3; the builder rejects non-positive values (use withDisableEagerActivities() to disable). --- src/Worker/WorkerOptions.php | 42 ++++++++++++++++++++++++ tests/Unit/DTO/WorkerOptionsTestCase.php | 23 +++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/Worker/WorkerOptions.php b/src/Worker/WorkerOptions.php index 4fe7fded9..50e159f31 100644 --- a/src/Worker/WorkerOptions.php +++ b/src/Worker/WorkerOptions.php @@ -278,6 +278,21 @@ class WorkerOptions #[Marshal(name: 'MaxConcurrentEagerActivityExecutionSize')] public int $maxConcurrentEagerActivityExecutionSize = 0; + /** + * Optional: Maximum number of activity slots that may be reserved for eager + * execution when completing a single workflow task. + * + * The default of null uses the underlying SDK default of 3. A configured + * value must be positive; to disable eager activity execution use + * {@see self::$disableEagerActivities} instead. + * + * @see self::$disableEagerActivities for a description of eager activity execution. + * + * @since RoadRunner 2025.1.16 + */ + #[Marshal(name: 'MaxEagerActivityReservationsPerWorkflowTask')] + public ?int $maxEagerActivityReservationsPerWorkflowTask = null; + /** * Optional: Disable allowing workflow and activity functions that are * registered with custom names from being able to be called with their @@ -787,6 +802,33 @@ public function withMaxConcurrentEagerActivityExecutionSize(int $size): self return $self; } + /** + * Optional: Maximum number of activity slots that may be reserved for eager + * execution when completing a single workflow task. + * + * The default of null uses the underlying SDK default of 3. A configured + * value must be positive; to disable eager activity execution use + * {@see self::withDisableEagerActivities()} instead. + * + * @see self::$disableEagerActivities for a description of eager activity execution. + * + * @since RoadRunner 2025.1.16 + */ + #[Pure] + public function withMaxEagerActivityReservationsPerWorkflowTask(int $value): self + { + if ($value <= 0) { + throw new \InvalidArgumentException( + 'MaxEagerActivityReservationsPerWorkflowTask must be positive; ' + . 'use withDisableEagerActivities() to disable eager activity execution.', + ); + } + + $self = clone $this; + $self->maxEagerActivityReservationsPerWorkflowTask = $value; + return $self; + } + /** * Optional: Disable allowing workflow and activity functions that are * registered with custom names from being able to be called with their diff --git a/tests/Unit/DTO/WorkerOptionsTestCase.php b/tests/Unit/DTO/WorkerOptionsTestCase.php index ad004b50a..73ecbbd9a 100644 --- a/tests/Unit/DTO/WorkerOptionsTestCase.php +++ b/tests/Unit/DTO/WorkerOptionsTestCase.php @@ -51,6 +51,7 @@ public function testMarshalling(): void 'MaxHeartbeatThrottleInterval' => null, 'DisableEagerActivities' => false, 'MaxConcurrentEagerActivityExecutionSize' => 0, + 'MaxEagerActivityReservationsPerWorkflowTask' => null, 'DisableRegistrationAliasing' => false, 'BuildID' => "", 'DeploymentOptions' => null, @@ -334,6 +335,28 @@ public function testMaxConcurrentEagerActivityExecutionSize(): void self::assertSame(10, $result->maxConcurrentEagerActivityExecutionSize); } + public function testMaxEagerActivityReservationsPerWorkflowTask(): void + { + $dto = new WorkerOptions(); + $result = $dto->withMaxEagerActivityReservationsPerWorkflowTask(10); + + self::assertNotSame($dto, $result); + self::assertNull($dto->maxEagerActivityReservationsPerWorkflowTask); + self::assertSame(10, $result->maxEagerActivityReservationsPerWorkflowTask); + self::assertSame(10, $this->marshal($result)['MaxEagerActivityReservationsPerWorkflowTask']); + } + + public function testMaxEagerActivityReservationsPerWorkflowTaskRejectsNonPositive(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage( + 'MaxEagerActivityReservationsPerWorkflowTask must be positive; ' + . 'use withDisableEagerActivities() to disable eager activity execution.', + ); + + (new WorkerOptions())->withMaxEagerActivityReservationsPerWorkflowTask(0); + } + public function testDisableRegistrationAliasing(): void { $dto = new WorkerOptions();