Skip to content

Commit ffabfef

Browse files
authored
Merge pull request #653: Expose RetryPolicy in Workflow context
2 parents 82ff905 + 33d0ac2 commit ffabfef

File tree

9 files changed

+183
-77
lines changed

9 files changed

+183
-77
lines changed

src/Common/RetryOptions.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class RetryOptions extends Options
6868
* is 1.0 then it is used for all retries.
6969
*/
7070
#[Marshal(name: 'initial_interval', type: DurationJsonType::class, nullable: true)]
71+
#[Marshal(name: 'InitialInterval', type: DurationJsonType::class, nullable: true)]
7172
public ?\DateInterval $initialInterval = self::DEFAULT_INITIAL_INTERVAL;
7273

7374
/**
@@ -77,6 +78,7 @@ class RetryOptions extends Options
7778
* Note: Must be greater than 1.0
7879
*/
7980
#[Marshal(name: 'backoff_coefficient')]
81+
#[Marshal(name: 'BackoffCoefficient')]
8082
public float $backoffCoefficient = self::DEFAULT_BACKOFF_COEFFICIENT;
8183

8284
/**
@@ -86,6 +88,7 @@ class RetryOptions extends Options
8688
* Default is 100x of {@see $initialInterval}.
8789
*/
8890
#[Marshal(name: 'maximum_interval', type: DurationJsonType::class, nullable: true)]
91+
#[Marshal(name: 'MaximumInterval', type: DurationJsonType::class, nullable: true)]
8992
public ?\DateInterval $maximumInterval = self::DEFAULT_MAXIMUM_INTERVAL;
9093

9194
/**
@@ -96,6 +99,7 @@ class RetryOptions extends Options
9699
* @var int<0, max>
97100
*/
98101
#[Marshal(name: 'maximum_attempts')]
102+
#[Marshal(name: 'MaximumAttempts')]
99103
public int $maximumAttempts = self::DEFAULT_MAXIMUM_ATTEMPTS;
100104

101105
/**
@@ -105,6 +109,7 @@ class RetryOptions extends Options
105109
* @var ExceptionsList
106110
*/
107111
#[Marshal(name: 'non_retryable_error_types')]
112+
#[Marshal(name: 'NonRetryableErrorTypes')]
108113
public array $nonRetryableExceptions = self::DEFAULT_NON_RETRYABLE_EXCEPTIONS;
109114

110115
public function mergeWith(?MethodRetry $retry = null): self

src/Internal/Marshaller/MarshallingRule.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@
1313

1414
use Temporal\Internal\Marshaller\Type\TypeInterface;
1515

16-
/**
17-
* @internal
18-
*/
1916
class MarshallingRule
2017
{
2118
/**

src/Internal/Marshaller/Type/ArrayType.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ public static function makeRule(\ReflectionProperty $property): ?MarshallingRule
6363
*/
6464
public function parse($value, $current): array
6565
{
66+
if ($value === null) {
67+
return [];
68+
}
69+
6670
if (!\is_array($value)) {
6771
throw new \InvalidArgumentException(\sprintf(self::ERROR_INVALID_TYPE, \get_debug_type($value)));
6872
}

src/Workflow/WorkflowInfo.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Temporal\Client\ClientOptions;
1717
use Temporal\Common\CronSchedule;
1818
use Temporal\Common\Priority;
19+
use Temporal\Common\RetryOptions;
1920
use Temporal\Common\TypedSearchAttributes;
2021
use Temporal\Internal\Marshaller\Meta\Marshal;
2122
use Temporal\Internal\Marshaller\Type\ArrayType;
@@ -143,6 +144,12 @@ final class WorkflowInfo
143144
#[Marshal(name: 'Priority')]
144145
public Priority $priority;
145146

147+
/**
148+
* @since SDK 2.16.0
149+
*/
150+
#[Marshal(name: 'RetryPolicy')]
151+
public ?RetryOptions $retryOptions = null;
152+
146153
/**
147154
* WorkflowInfo constructor.
148155
*/
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Temporal\Tests\Acceptance\Extra\Activity\ActivityInfo;
6+
7+
use PHPUnit\Framework\Attributes\Test;
8+
use React\Promise\PromiseInterface;
9+
use Temporal\Activity;
10+
use Temporal\Client\WorkflowStubInterface;
11+
use Temporal\Common\RetryOptions;
12+
use Temporal\Tests\Acceptance\App\Attribute\Stub;
13+
use Temporal\Tests\Acceptance\App\TestCase;
14+
use Temporal\Workflow;
15+
use Temporal\Workflow\WorkflowInterface;
16+
use Temporal\Workflow\WorkflowMethod;
17+
18+
class ActivityInfoTest extends TestCase
19+
{
20+
#[Test]
21+
public static function retryPolicy(
22+
#[Stub('Extra_Activity_ActivityInfo', args: [TestWorkflow::ARG_RETRY_OPTIONS])]
23+
WorkflowStubInterface $stub,
24+
): void {
25+
self::markTestSkipped('See https://github.com/temporalio/sdk-php/issues/602');
26+
27+
$result = $stub->getResult(type: 'array');
28+
self::assertSame([
29+
"initial_interval" => ['seconds' => 1, 'nanos' => 0],
30+
"backoff_coefficient" => 3,
31+
"maximum_interval" => ['seconds' => 120, 'nanos' => 0],
32+
"maximum_attempts" => 20,
33+
"non_retryable_error_types" => [],
34+
], $result);
35+
}
36+
}
37+
38+
39+
#[WorkflowInterface]
40+
class TestWorkflow
41+
{
42+
public const ARG_RETRY_OPTIONS = 'retryPolicy';
43+
44+
#[WorkflowMethod(name: "Extra_Activity_ActivityInfo")]
45+
public function handle(string $arg)
46+
{
47+
return yield match ($arg) {
48+
self::ARG_RETRY_OPTIONS => $this->getRetryOptions(),
49+
};
50+
}
51+
52+
private function getRetryOptions(): PromiseInterface
53+
{
54+
return Workflow::newActivityStub(
55+
TestActivity::class,
56+
Activity\ActivityOptions::new()
57+
->withRetryOptions(
58+
RetryOptions::new()
59+
->withMaximumAttempts(20)
60+
->withBackoffCoefficient(3.0)
61+
->withInitialInterval('1 second')
62+
->withMaximumInterval('2 minutes'),
63+
)
64+
->withScheduleToCloseTimeout(10),
65+
)
66+
->retryOptions();
67+
}
68+
}
69+
70+
#[Activity\ActivityInterface(prefix: 'Extra_Activity_ActivityInfo.')]
71+
class TestActivity
72+
{
73+
#[Activity\ActivityMethod]
74+
public function retryOptions()
75+
{
76+
return Activity::getInfo()->retryOptions;
77+
}
78+
}

tests/Acceptance/Extra/Workflow/RootWorkflowExecutionTest.php

Lines changed: 0 additions & 58 deletions
This file was deleted.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Temporal\Tests\Acceptance\Extra\Workflow\WorkflowInfo;
6+
7+
use PHPUnit\Framework\Attributes\Test;
8+
use Temporal\Client\WorkflowStubInterface;
9+
use Temporal\Tests\Acceptance\App\Attribute\RetryOptions;
10+
use Temporal\Tests\Acceptance\App\Attribute\Stub;
11+
use Temporal\Tests\Acceptance\App\TestCase;
12+
use Temporal\Workflow;
13+
use Temporal\Workflow\WorkflowInterface;
14+
use Temporal\Workflow\WorkflowMethod;
15+
16+
class WorkflowInfoTest extends TestCase
17+
{
18+
#[Test]
19+
public static function rootWorkflowExecution(
20+
#[Stub('Extra_Workflow_WorkflowInfo', args: [MainWorkflow::ARG_ROOT_EXECUTION])]
21+
WorkflowStubInterface $stub,
22+
): void {
23+
$result = $stub->getResult(type: 'array');
24+
self::assertSame([
25+
'ID' => $stub->getExecution()->getID(),
26+
'RunID' => $stub->getExecution()->getRunID(),
27+
], $result);
28+
}
29+
30+
#[Test]
31+
public static function retryOptions(
32+
#[Stub('Extra_Workflow_WorkflowInfo', args: [MainWorkflow::ARG_RETRY_OPTIONS], retryOptions: new RetryOptions(
33+
backoffCoefficient: 3.0,
34+
maximumInterval: '2 minutes',
35+
maximumAttempts: 10,
36+
))]
37+
WorkflowStubInterface $stub,
38+
): void {
39+
$result = $stub->getResult(type: 'array');
40+
self::assertEquals([
41+
"initial_interval" => ['seconds' => 1, 'nanos' => 0],
42+
"backoff_coefficient" => 3,
43+
"maximum_interval" => ['seconds' => 120, 'nanos' => 0],
44+
"maximum_attempts" => 10,
45+
"non_retryable_error_types" => [],
46+
], $result);
47+
}
48+
}
49+
50+
#[WorkflowInterface]
51+
class MainWorkflow
52+
{
53+
public const ARG_RETRY_OPTIONS = 'retryPolicy';
54+
public const ARG_ROOT_EXECUTION = 'rootExecution';
55+
56+
#[WorkflowMethod('Extra_Workflow_WorkflowInfo')]
57+
public function run($arg)
58+
{
59+
return yield match ($arg) {
60+
self::ARG_ROOT_EXECUTION => Workflow::newChildWorkflowStub(ChildWorkflow::class)->run(),
61+
self::ARG_RETRY_OPTIONS => Workflow::getCurrentContext()->getInfo()->retryOptions,
62+
};
63+
}
64+
}
65+
66+
#[WorkflowInterface]
67+
class ChildWorkflow
68+
{
69+
#[WorkflowMethod('Extra_Workflow_WorkflowInfo_Child')]
70+
public function run()
71+
{
72+
return yield Workflow::newChildWorkflowStub(ChildWorkflow2::class)->run();
73+
}
74+
}
75+
76+
#[WorkflowInterface]
77+
class ChildWorkflow2
78+
{
79+
#[WorkflowMethod('Extra_Workflow_WorkflowInfo_Child2')]
80+
public function run()
81+
{
82+
return Workflow::getCurrentContext()->getInfo()->rootExecution;
83+
}
84+
}

tests/Unit/DTO/Type/ArrayType/ArrayTestCase.php

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,23 +76,11 @@ public function testUnmarshalling(): void
7676

7777
public function testSetNullToNotNullable(): void
7878
{
79-
try {
80-
$this->unmarshal([
81-
'foo' => null,
82-
], new ArrayDto());
79+
$dto = $this->unmarshal([
80+
'foo' => null,
81+
], new ArrayDto());
8382

84-
$this->fail('Null value should not be allowed.');
85-
} catch (\Throwable $e) {
86-
$this->assertStringContainsString(
87-
'`foo`',
88-
$e->getMessage(),
89-
);
90-
$this->assertInstanceOf(\InvalidArgumentException::class, $e->getPrevious());
91-
$this->assertStringContainsString(
92-
'Passed value must be a type of array, but null given',
93-
$e->getPrevious()->getMessage(),
94-
);
95-
}
83+
self::assertSame([], $dto->foo);
9684
}
9785

9886
protected function getTypeMatchers(): array

tests/Unit/DTO/WorkflowInfoTestCase.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public function testMarshalling(): void
5151
'Priority' => [
5252
'priority_key' => 0,
5353
],
54+
'RetryPolicy' => null,
5455
];
5556

5657
$this->assertSame($expected, $this->marshal($dto));

0 commit comments

Comments
 (0)