Skip to content

Commit c84754a

Browse files
authored
Expose Workflow::upsertMemo() (#562)
* Add `Workflow::upsertMemo()` implementation * Add memo test Fix internal issues Workflow::info's memo is now converted to values array * Update required RoadRunner version and docs * Fix psalm issues
2 parents e11306c + db804e0 commit c84754a

File tree

11 files changed

+362
-86
lines changed

11 files changed

+362
-86
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"roadrunner-php/roadrunner-api-dto": "^1.10.0",
3535
"roadrunner-php/version-checker": "^1.0.1",
3636
"spiral/attributes": "^3.1.8",
37-
"spiral/roadrunner": "^2024.3.2",
37+
"spiral/roadrunner": "^2024.3.3",
3838
"spiral/roadrunner-cli": "^2.6",
3939
"spiral/roadrunner-kv": "^4.3",
4040
"spiral/roadrunner-worker": "^3.6.1",

psalm-baseline.xml

Lines changed: 2 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="6.2.0@814dfde37b43a1fe6d9b0996e08b19661af53bc5">
2+
<files psalm-version="6.4.1@09a200c15910905ddc49e5edd37b73f9c78f7580">
33
<file src="src/Activity.php">
44
<ImplicitToStringCast>
55
<code><![CDATA[$type]]></code>
@@ -984,89 +984,11 @@
984984
<code><![CDATA[PromiseInterface]]></code>
985985
</TooManyTemplateParams>
986986
</file>
987-
<file src="src/Internal/Transport/Request/Cancel.php">
988-
<MissingImmutableAnnotation>
989-
<code><![CDATA[Cancel]]></code>
990-
</MissingImmutableAnnotation>
991-
</file>
992-
<file src="src/Internal/Transport/Request/CancelExternalWorkflow.php">
993-
<MissingImmutableAnnotation>
994-
<code><![CDATA[CancelExternalWorkflow]]></code>
995-
</MissingImmutableAnnotation>
996-
</file>
997-
<file src="src/Internal/Transport/Request/CompleteWorkflow.php">
998-
<MissingImmutableAnnotation>
999-
<code><![CDATA[CompleteWorkflow]]></code>
1000-
</MissingImmutableAnnotation>
1001-
</file>
1002-
<file src="src/Internal/Transport/Request/ContinueAsNew.php">
1003-
<MissingImmutableAnnotation>
1004-
<code><![CDATA[ContinueAsNew]]></code>
1005-
</MissingImmutableAnnotation>
1006-
</file>
1007-
<file src="src/Internal/Transport/Request/ExecuteActivity.php">
1008-
<MissingImmutableAnnotation>
1009-
<code><![CDATA[ExecuteActivity]]></code>
1010-
</MissingImmutableAnnotation>
1011-
</file>
1012-
<file src="src/Internal/Transport/Request/ExecuteChildWorkflow.php">
1013-
<MissingImmutableAnnotation>
1014-
<code><![CDATA[ExecuteChildWorkflow]]></code>
1015-
</MissingImmutableAnnotation>
1016-
</file>
1017-
<file src="src/Internal/Transport/Request/ExecuteLocalActivity.php">
1018-
<MissingImmutableAnnotation>
1019-
<code><![CDATA[ExecuteLocalActivity]]></code>
1020-
</MissingImmutableAnnotation>
1021-
</file>
1022-
<file src="src/Internal/Transport/Request/GetChildWorkflowExecution.php">
1023-
<MissingImmutableAnnotation>
1024-
<code><![CDATA[GetChildWorkflowExecution]]></code>
1025-
</MissingImmutableAnnotation>
1026-
</file>
1027-
<file src="src/Internal/Transport/Request/GetVersion.php">
1028-
<MissingImmutableAnnotation>
1029-
<code><![CDATA[GetVersion]]></code>
1030-
</MissingImmutableAnnotation>
1031-
</file>
1032987
<file src="src/Internal/Transport/Request/NewTimer.php">
1033-
<MissingImmutableAnnotation>
1034-
<code><![CDATA[NewTimer]]></code>
1035-
</MissingImmutableAnnotation>
1036988
<PossiblyNullPropertyFetch>
1037989
<code><![CDATA[CarbonInterval::make($interval)->totalMilliseconds]]></code>
1038990
</PossiblyNullPropertyFetch>
1039991
</file>
1040-
<file src="src/Internal/Transport/Request/Panic.php">
1041-
<MissingImmutableAnnotation>
1042-
<code><![CDATA[Panic]]></code>
1043-
</MissingImmutableAnnotation>
1044-
</file>
1045-
<file src="src/Internal/Transport/Request/SideEffect.php">
1046-
<MissingImmutableAnnotation>
1047-
<code><![CDATA[SideEffect]]></code>
1048-
</MissingImmutableAnnotation>
1049-
</file>
1050-
<file src="src/Internal/Transport/Request/SignalExternalWorkflow.php">
1051-
<MissingImmutableAnnotation>
1052-
<code><![CDATA[SignalExternalWorkflow]]></code>
1053-
</MissingImmutableAnnotation>
1054-
</file>
1055-
<file src="src/Internal/Transport/Request/UndefinedResponse.php">
1056-
<MissingImmutableAnnotation>
1057-
<code><![CDATA[UndefinedResponse]]></code>
1058-
</MissingImmutableAnnotation>
1059-
</file>
1060-
<file src="src/Internal/Transport/Request/UpsertSearchAttributes.php">
1061-
<MissingImmutableAnnotation>
1062-
<code><![CDATA[UpsertSearchAttributes]]></code>
1063-
</MissingImmutableAnnotation>
1064-
</file>
1065-
<file src="src/Internal/Transport/Request/UpsertTypedSearchAttributes.php">
1066-
<MissingImmutableAnnotation>
1067-
<code><![CDATA[UpsertTypedSearchAttributes]]></code>
1068-
</MissingImmutableAnnotation>
1069-
</file>
1070992
<file src="src/Internal/Transport/Router/CancelWorkflow.php">
1071993
<DocblockTypeContradiction>
1072994
<code><![CDATA[$process === null]]></code>
@@ -1127,6 +1049,7 @@
11271049
<file src="src/Internal/Transport/Router/StartWorkflow.php">
11281050
<PossiblyFalseArgument>
11291051
<code><![CDATA[\json_encode($param)]]></code>
1052+
<code><![CDATA[\json_encode($param)]]></code>
11301053
</PossiblyFalseArgument>
11311054
<UnnecessaryVarAnnotation>
11321055
<code><![CDATA[Input]]></code>
@@ -1427,11 +1350,6 @@
14271350
<code><![CDATA[$this->failure]]></code>
14281351
</NullableReturnStatement>
14291352
</file>
1430-
<file src="src/Worker/Transport/Command/Client/Request.php">
1431-
<MissingImmutableAnnotation>
1432-
<code><![CDATA[Request]]></code>
1433-
</MissingImmutableAnnotation>
1434-
</file>
14351353
<file src="src/Worker/Transport/Command/Client/SuccessClientResponse.php">
14361354
<InvalidNullableReturnType>
14371355
<code><![CDATA[ValuesInterface]]></code>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/**
4+
* This file is part of Temporal package.
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace Temporal\Interceptor\WorkflowOutboundCalls;
13+
14+
/**
15+
* @psalm-immutable
16+
*/
17+
final class UpsertMemoInput
18+
{
19+
/**
20+
* @param array<non-empty-string, mixed> $memo
21+
*
22+
* @no-named-arguments
23+
* @internal Don't use the constructor. Use {@see self::with()} instead.
24+
*/
25+
public function __construct(
26+
public readonly array $memo,
27+
) {}
28+
29+
public function with(
30+
?array $memo = null,
31+
): self {
32+
return new self(
33+
$memo ?? $this->memo,
34+
);
35+
}
36+
}

src/Interceptor/WorkflowOutboundCallsInterceptor.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use Temporal\Interceptor\WorkflowOutboundCalls\SideEffectInput;
2727
use Temporal\Interceptor\WorkflowOutboundCalls\SignalExternalWorkflowInput;
2828
use Temporal\Interceptor\WorkflowOutboundCalls\TimerInput;
29+
use Temporal\Interceptor\WorkflowOutboundCalls\UpsertMemoInput;
2930
use Temporal\Interceptor\WorkflowOutboundCalls\UpsertSearchAttributesInput;
3031
use Temporal\Interceptor\WorkflowOutboundCalls\UpsertTypedSearchAttributesInput;
3132
use Temporal\Internal\Interceptor\Interceptor;
@@ -113,6 +114,11 @@ public function continueAsNew(ContinueAsNewInput $input, callable $next): Promis
113114
*/
114115
public function getVersion(GetVersionInput $input, callable $next): PromiseInterface;
115116

117+
/**
118+
* @param callable(UpsertMemoInput): PromiseInterface $next
119+
*/
120+
public function upsertMemo(UpsertMemoInput $input, callable $next): PromiseInterface;
121+
116122
/**
117123
* @param callable(UpsertSearchAttributesInput): PromiseInterface $next
118124
*/
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Temporal\Internal\Transport\Request;
6+
7+
use Temporal\Worker\Transport\Command\Client\Request;
8+
9+
final class UpsertMemo extends Request
10+
{
11+
public const NAME = 'UpsertMemo';
12+
13+
/**
14+
* @param array<string, mixed> $memo
15+
*/
16+
public function __construct(
17+
private readonly array $memo,
18+
) {
19+
parent::__construct(self::NAME, ['memo' => (object) $memo]);
20+
}
21+
22+
/**
23+
* @return array<string, mixed>
24+
*/
25+
public function getMemo(): array
26+
{
27+
return $this->memo;
28+
}
29+
}

src/Internal/Transport/Router/StartWorkflow.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Temporal\Internal\Transport\Router;
1313

1414
use React\Promise\Deferred;
15+
use Temporal\Api\Common\V1\Memo;
1516
use Temporal\Api\Common\V1\SearchAttributes;
1617
use Temporal\Common\TypedSearchAttributes;
1718
use Temporal\DataConverter\EncodedCollection;
@@ -58,8 +59,10 @@ public function handle(ServerRequestInterface $request, array $headers, Deferred
5859

5960
// Search Attributes and Typed Search Attributes
6061
$searchAttributes = $this->convertSearchAttributes($options['info']['SearchAttributes'] ?? null);
62+
$memo = $this->convertMemo($options['info']['Memo'] ?? null);
6163
$options['info']['SearchAttributes'] = $searchAttributes?->getValues();
6264
$options['info']['TypedSearchAttributes'] = $this->prepareTypedSA($options['search_attributes'] ?? null);
65+
$options['info']['Memo'] = $memo?->getValues();
6366

6467
/** @var Input $input */
6568
$input = $this->services->marshaller->unmarshal($options, new Input());
@@ -156,6 +159,32 @@ private function convertSearchAttributes(?array $param): ?EncodedCollection
156159
}
157160
}
158161

162+
private function convertMemo(?array $param): ?EncodedCollection
163+
{
164+
if (!\is_array($param)) {
165+
return null;
166+
}
167+
168+
if ($param === []) {
169+
return EncodedCollection::empty();
170+
}
171+
172+
try {
173+
$memo = (new Memo());
174+
$memo->mergeFromJsonString(
175+
\json_encode($param),
176+
true,
177+
);
178+
179+
return EncodedCollection::fromPayloadCollection(
180+
$memo->getFields(),
181+
$this->services->dataConverter,
182+
);
183+
} catch (\Throwable) {
184+
return null;
185+
}
186+
}
187+
159188
private function prepareTypedSA(?array $param): TypedSearchAttributes
160189
{
161190
return $param === null

src/Internal/Workflow/WorkflowContext.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use Temporal\Interceptor\WorkflowOutboundCalls\PanicInput;
3636
use Temporal\Interceptor\WorkflowOutboundCalls\SideEffectInput;
3737
use Temporal\Interceptor\WorkflowOutboundCalls\TimerInput;
38+
use Temporal\Interceptor\WorkflowOutboundCalls\UpsertMemoInput;
3839
use Temporal\Interceptor\WorkflowOutboundCalls\UpsertSearchAttributesInput;
3940
use Temporal\Interceptor\WorkflowOutboundCalls\UpsertTypedSearchAttributesInput;
4041
use Temporal\Interceptor\WorkflowOutboundCallsInterceptor;
@@ -55,6 +56,7 @@
5556
use Temporal\Internal\Transport\Request\NewTimer;
5657
use Temporal\Internal\Transport\Request\Panic;
5758
use Temporal\Internal\Transport\Request\SideEffect;
59+
use Temporal\Internal\Transport\Request\UpsertMemo;
5860
use Temporal\Internal\Transport\Request\UpsertSearchAttributes;
5961
use Temporal\Internal\Transport\Request\UpsertTypedSearchAttributes;
6062
use Temporal\Internal\Workflow\Process\HandlerState;
@@ -448,10 +450,43 @@ public function allHandlersFinished(): bool
448450
return !$this->handlers->hasRunningHandlers();
449451
}
450452

453+
public function upsertMemo(array $values): void
454+
{
455+
$this->callsInterceptor->with(
456+
function (UpsertMemoInput $input): PromiseInterface {
457+
if ($input->memo === []) {
458+
return resolve();
459+
}
460+
461+
$result = $this->request(new UpsertMemo($input->memo), false);
462+
463+
/** @psalm-suppress UnsupportedPropertyReferenceUsage $memo */
464+
$memo = &$this->input->info->memo;
465+
$memo ??= [];
466+
foreach ($input->memo as $name => $value) {
467+
if ($value === null) {
468+
unset($memo[$name]);
469+
continue;
470+
}
471+
472+
$memo[$name] = $value;
473+
}
474+
475+
return $result;
476+
},
477+
/** @see WorkflowOutboundCallsInterceptor::upsertMemo() */
478+
'upsertMemo',
479+
)(new UpsertMemoInput($values));
480+
}
481+
451482
public function upsertSearchAttributes(array $searchAttributes): void
452483
{
453484
$this->callsInterceptor->with(
454485
function (UpsertSearchAttributesInput $input): PromiseInterface {
486+
if ($input->searchAttributes === []) {
487+
return resolve();
488+
}
489+
455490
$result = $this->request(new UpsertSearchAttributes($input->searchAttributes), false);
456491

457492
/** @psalm-suppress UnsupportedPropertyReferenceUsage $sa */
@@ -476,6 +511,10 @@ public function upsertTypedSearchAttributes(SearchAttributeUpdate ...$updates):
476511
{
477512
$this->callsInterceptor->with(
478513
function (UpsertTypedSearchAttributesInput $input): PromiseInterface {
514+
if ($input->updates === []) {
515+
return resolve();
516+
}
517+
479518
$result = $this->request(new UpsertTypedSearchAttributes($input->updates), false);
480519

481520
// Merge changes

src/Worker/Transport/Command/Common/RequestTrait.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ public function getHeader(): Header
3030
return $this->header;
3131
}
3232

33+
/**
34+
* @psalm-external-mutation-free
35+
*/
3336
public function withHeader(HeaderInterface $header): self
3437
{
3538
$clone = clone $this;

0 commit comments

Comments
 (0)