diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 29cf6ce4..fdae7573 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1178,6 +1178,7 @@ + currentDetails = &$context->currentDetails]]> trace = &$context->trace]]> diff --git a/src/DataConverter/ProtoJsonConverter.php b/src/DataConverter/ProtoJsonConverter.php index 34daf659..493f1dde 100644 --- a/src/DataConverter/ProtoJsonConverter.php +++ b/src/DataConverter/ProtoJsonConverter.php @@ -50,7 +50,13 @@ public function toPayload($value): ?Payload public function fromPayload(Payload $payload, Type $type) { if (!$type->isClass()) { - throw new DataConverterException('Unable to decode value using protobuf converter - '); + throw new DataConverterException( + \sprintf( + 'Unable to decode value using "%s" encoding converter: resulting type must be a class, "%s" given', + $this->getEncodingType(), + $type->getName(), + ), + ); } try { diff --git a/src/Internal/Transport/Router/InvokeQuery.php b/src/Internal/Transport/Router/InvokeQuery.php index 30ba6b96..b19580b7 100644 --- a/src/Internal/Transport/Router/InvokeQuery.php +++ b/src/Internal/Transport/Router/InvokeQuery.php @@ -122,12 +122,14 @@ private function workflowMetadata(Deferred $resolver, WorkflowContext $context): static function () use ($resolver, $context): void { try { $result = EncodedValues::fromValues([ - (new WorkflowMetadata())->setDefinition( - (new WorkflowDefinition()) - ->setQueryDefinitions($context->getQueryDispatcher()->getQueryHandlers()) - ->setSignalDefinitions($context->getSignalDispatcher()->getSignalHandlers()) - ->setUpdateDefinitions($context->getUpdateDispatcher()->getUpdateHandlers()), - ), + (new WorkflowMetadata()) + ->setDefinition( + (new WorkflowDefinition()) + ->setQueryDefinitions($context->getQueryDispatcher()->getQueryHandlers()) + ->setSignalDefinitions($context->getSignalDispatcher()->getSignalHandlers()) + ->setUpdateDefinitions($context->getUpdateDispatcher()->getUpdateHandlers()), + ) + ->setCurrentDetails((string) $context->getCurrentDetails()), ]); $resolver->resolve($result); diff --git a/src/Internal/Workflow/ScopeContext.php b/src/Internal/Workflow/ScopeContext.php index bff6743a..b9a3ebab 100644 --- a/src/Internal/Workflow/ScopeContext.php +++ b/src/Internal/Workflow/ScopeContext.php @@ -57,6 +57,7 @@ public static function fromWorkflowContext( $ctx->readonly = $context->readonly; $ctx->continueAsNew = $context->continueAsNew; $ctx->trace = &$context->trace; + $ctx->currentDetails = &$context->currentDetails; return $ctx; } diff --git a/src/Internal/Workflow/WorkflowContext.php b/src/Internal/Workflow/WorkflowContext.php index 26e8fb84..5fc887cb 100644 --- a/src/Internal/Workflow/WorkflowContext.php +++ b/src/Internal/Workflow/WorkflowContext.php @@ -99,6 +99,7 @@ class WorkflowContext implements WorkflowContextInterface, HeaderCarrier, Destro protected array $trace = []; protected bool $continueAsNew = false; protected bool $readonly = true; + protected ?string $currentDetails = null; /** @var Pipeline */ private Pipeline $requestInterceptor; @@ -723,6 +724,22 @@ public function getUpdateDispatcher(): UpdateDispatcher return $this->updateDispatcher; } + /** + * Get the current details of the workflow execution. + */ + public function getCurrentDetails(): ?string + { + return $this->currentDetails; + } + + /** + * Set the current details of the workflow execution. + */ + public function setCurrentDetails(?string $details): void + { + $this->currentDetails = $details; + } + protected function awaitRequest(callable|Mutex|PromiseInterface ...$conditions): PromiseInterface { $result = []; diff --git a/src/Workflow.php b/src/Workflow.php index 5712ef60..e8927f88 100644 --- a/src/Workflow.php +++ b/src/Workflow.php @@ -604,6 +604,22 @@ public static function timer($interval, ?TimerOptions $options = null): PromiseI return self::getCurrentContext()->timer($interval, $options); } + /** + * Get the current details of the workflow execution. + */ + public static function getCurrentDetails(): ?string + { + return self::getCurrentContext()->getCurrentDetails(); + } + + /** + * Set the current details of the workflow execution. + */ + public static function setCurrentDetails(?string $details): void + { + self::getCurrentContext()->setCurrentDetails($details); + } + /** * Completes the current workflow execution atomically and starts a new execution with the same Workflow Id. * diff --git a/src/Workflow/WorkflowContextInterface.php b/src/Workflow/WorkflowContextInterface.php index 945eda1c..30548a8f 100644 --- a/src/Workflow/WorkflowContextInterface.php +++ b/src/Workflow/WorkflowContextInterface.php @@ -445,4 +445,14 @@ public function getLogger(): LoggerInterface; * Get the currently running Workflow instance. */ public function getInstance(): object; + + /** + * Get the current details of the workflow execution. + */ + public function getCurrentDetails(): ?string; + + /** + * Set the current details of the workflow execution. + */ + public function setCurrentDetails(?string $details): void; } diff --git a/tests/Acceptance/Extra/Workflow/WorkflowMetadataTest.php b/tests/Acceptance/Extra/Workflow/WorkflowMetadataTest.php new file mode 100644 index 00000000..4a90e47b --- /dev/null +++ b/tests/Acceptance/Extra/Workflow/WorkflowMetadataTest.php @@ -0,0 +1,60 @@ +query('__temporal_workflow_metadata'); + /** + * @var WorkflowMetadata|null $metadata + */ + $metadata = $values->getValue(0, WorkflowMetadata::class); + + $stub->signal('exit'); + $this->assertSame("Cooking workflow from test", $metadata->getCurrentDetails()); + } +} + +#[WorkflowInterface] +class TestWorkflow +{ + private bool $exit = false; + + #[WorkflowMethod(name: "Extra_Workflow_WorkflowMetadata")] + public function handle(string $payload) + { + Workflow::setCurrentDetails("Cooking workflow " . $payload); + + yield Workflow::await(fn() => $this->exit); + } + + /** + * @return null|non-empty-string + */ + #[Workflow\QueryMethod] + public function getCurrentDetails(): ?string + { + return Workflow::getCurrentDetails(); + } + + #[Workflow\SignalMethod] + public function exit(): void + { + $this->exit = true; + } +}