From b29986e8b42bd09faa6812c9def89af8a7feeb6a Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Thu, 17 Oct 2024 17:00:57 +0400 Subject: [PATCH 01/13] Add `Message handler patterns` headers from python docs --- docs/develop/php/message-passing.mdx | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index aa71ab9240..0f4b2b47ce 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -2,7 +2,7 @@ id: message-passing title: Workflow message passing - PHP SDK sidebar_label: Messages -toc_max_heading_level: 2 +toc_max_heading_level: 3 keywords: - message passing - signals @@ -495,3 +495,28 @@ $resultUuid = $stub->startUpdate( ->withResultType(UuidInterface::class) )->getResult(); ``` + +## Message handler patterns {#message-handler-patterns} + +This section covers common write operations, such as Signal and Update handlers. +It doesn't apply to pure read operations, like Queries or Update Validators. + +:::tip + +For additional information, see [Inject work into the main Workflow](/encyclopedia/workflow-message-passing#injecting-work-into-main-workflow), [Ensuring your messages are processed exactly once](/encyclopedia/workflow-message-passing#exactly-once-message-processing), and [this sample](https://github.com/temporalio/samples-php/tree/master/app/src/SafeMessageHandlers) demonstrating safe `async` message handling. + +::: + +### Add async handlers to use `await` {#async-handlers} + + +### Add wait conditions to block + + +### Use wait conditions in handlers + + +### Ensure your handlers finish before the Workflow completes {#wait-for-message-handlers} + + +### Use `Mutex` to prevent concurrent handler execution {#control-handler-concurrency} From d7f0082f93c9cdd2d5f3d73f9a105fb7e4cde75e Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Thu, 17 Oct 2024 20:26:38 +0400 Subject: [PATCH 02/13] Describe Workflow::allHandlersFinished --- docs/develop/php/message-passing.mdx | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index 0f4b2b47ce..fa9c45fbef 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -518,5 +518,33 @@ For additional information, see [Inject work into the main Workflow](/encycloped ### Ensure your handlers finish before the Workflow completes {#wait-for-message-handlers} +Workflow wait conditions can ensure your handler completes before a Workflow finishes. +When your Workflow uses async Signal or Update handlers, your main Workflow method can return or continue-as-new while a handler is still waiting on an async task, such as an Activity result. +The Workflow completing may interrupt the handler before it finishes crucial work and cause client errors when trying retrieve Update results. +Use [`Workflow::await()`](https://php.temporal.io/classes/Temporal-Workflow.html#method_await) and [`Workflow::allHandlersFinished()`](https://php.temporal.io/classes/Temporal-Workflow.html#method_allHandlersFinished) to address this problem and allow your Workflow to end smoothly: + +```php +#[WorkflowInterface] +class MyWorkflow { + #[WorkflowMethod] + public function run() { + // ... + yield Workflow::await(fn() => Workflow::allHandlersFinished()); + return "workflow-result"; + } +} +``` + +By default, your Worker will log a warning when you allow a Workflow Execution to finish with unfinished handler executions. +You can silence these warnings on a per-handler basis by passing the `unfinishedPolicy` argument to the [`UpdateMethod`](https://php.temporal.io/classes/Temporal-Workflow-UpdateMethod.html) / [`SignalMethod`](https://php.temporal.io/classes/Temporal-Workflow-SignalMethod.html) attribute: + +```php + #[UpdateMethod(unfinishedPolicy: HandlerUnfinishedPolicy::Abandon)] + public function myUpdate() { + // ... + } +``` + +See [Finishing handlers before the Workflow completes](/encyclopedia/workflow-message-passing#finishing-message-handlers) for more information. ### Use `Mutex` to prevent concurrent handler execution {#control-handler-concurrency} From c27089d630fb367dc5c792153e05eec4e9ac7d24 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Fri, 18 Oct 2024 13:23:54 +0400 Subject: [PATCH 03/13] Describe "Add wait conditions to block" --- docs/develop/php/message-passing.mdx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index fa9c45fbef..9d48af8d1b 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -512,6 +512,17 @@ For additional information, see [Inject work into the main Workflow](/encycloped ### Add wait conditions to block +Sometimes, async Signal or Update handlers need to meet certain conditions before they should continue. +You can use a wait condition ([`Workflow::await()`](https://php.temporal.io/classes/Temporal-Workflow.html#method_await)) to set a function that prevents the code from proceeding until the condition returns `True`. +This is an important feature that helps you control your handler logic. + +Here are two important use cases for `Workflow::await()`: + +- Waiting in a handler until it is appropriate to continue. +- Waiting in the main Workflow until all active handlers have finished. + +The condition state you're waiting for can be updated by and reflect any part of the Workflow code. +This includes the main Workflow method, other handlers, or child coroutines spawned by the main Workflow method (see [`Workflow::async()`](https://php.temporal.io/classes/Temporal-Workflow.html#method_async). ### Use wait conditions in handlers From abc61019f230c7be800ecc505661260c799bba31 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Fri, 18 Oct 2024 16:09:23 +0400 Subject: [PATCH 04/13] Describe mutex usage in concurrent handler execution --- docs/develop/php/message-passing.mdx | 65 +++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index 9d48af8d1b..9228806768 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -513,7 +513,7 @@ For additional information, see [Inject work into the main Workflow](/encycloped ### Add wait conditions to block Sometimes, async Signal or Update handlers need to meet certain conditions before they should continue. -You can use a wait condition ([`Workflow::await()`](https://php.temporal.io/classes/Temporal-Workflow.html#method_await)) to set a function that prevents the code from proceeding until the condition returns `True`. +You can use a wait condition ([`Workflow::await()`](https://php.temporal.io/classes/Temporal-Workflow.html#method_await)) to set a function that prevents the code from proceeding until the condition returns `true`. This is an important feature that helps you control your handler logic. Here are two important use cases for `Workflow::await()`: @@ -559,3 +559,66 @@ You can silence these warnings on a per-handler basis by passing the `unfinished See [Finishing handlers before the Workflow completes](/encyclopedia/workflow-message-passing#finishing-message-handlers) for more information. ### Use `Mutex` to prevent concurrent handler execution {#control-handler-concurrency} + +Concurrent processes can interact in unpredictable ways. +Incorrectly written [concurrent message-passing](/encyclopedia/workflow-message-passing#message-handler-concurrency) code may not work correctly when multiple handler instances run simultaneously. +Here's an example of a pathological case: + +```php +#[WorkflowInterface] +class MyWorkflow +{ + // ... + + #[SignalMethod] + public function badAsyncHandler() + { + $data = yield Workflow::executeActivity( + type: 'fetch_data', + args: ['url' => 'http://example.com'], + options: ActivityOptions::new()->withStartToCloseTimeout('10 seconds'), + ); + $this->x = $data->x; + # ๐Ÿ›๐Ÿ› Bug!! If multiple instances of this handler are executing concurrently, then + # there may be times when the Workflow has $this->x from one Activity execution and $this->y from another. + yield Workflow::timer(1); # or await anything else + $this->y = $data->y; + } +} +``` + +Coordinating access using `Mutex` corrects this code. +Locking makes sure that only one handler instance can execute a specific section of code at any given time: + +```php +use Temporal\Workflow; + +#[Workflow\WorkflowInterface] +class MyWorkflow +{ + // ... + + private Workflow\Mutex $mutex; + + public function __construct() + { + $this->mutex = new Workflow\Mutex(); + } + + #[Workflow\SignalMethod] + public function safeAsyncHandler() + { + $data = yield Workflow::executeActivity( + type: 'fetch_data', + args: ['url' => 'http://example.com'], + options: ActivityOptions::new()->withStartToCloseTimeout('10 seconds'), + ); + yield Workflow::runLocked($this->mutex, function () use ($data) { + $this->x = $data->x; + # โœ… OK: the scheduler may switch now to a different handler execution, or to the main workflow + # method, but no other execution of this handler can run until this execution finishes. + yield Workflow::timer(1); # or await anything else + $this->y = $data->y; + }); + } +``` From e8866c6fadf307276a2f17725a007f81939fc0ac Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Fri, 18 Oct 2024 17:01:14 +0400 Subject: [PATCH 05/13] Describe "Use wait conditions in handlers" --- docs/develop/php/message-passing.mdx | 29 +++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index 9228806768..54a457fd7f 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -526,6 +526,26 @@ This includes the main Workflow method, other handlers, or child coroutines spaw ### Use wait conditions in handlers +It's common to use a Workflow wait condition to wait until a handler should start. +You can also use wait conditions anywhere else in the handler to wait for a specific condition to become `true`. +This allows you to write handlers that pause at multiple points, each time waiting for a required condition to become `true`. + +Consider a `readyForUpdateToExecute` method that runs before your Update handler executes. +The `Workflow::await` method waits until your condition is met: + +```php + #[UpdateMethod] + public function myUpdate(UpdateInput $input) + { + yield Workflow::await( + fn() => $this->readyForUpdateToExecute($input), + ); + + // ... + } +``` + +Remember: Handlers can execute before the main Workflow method starts. ### Ensure your handlers finish before the Workflow completes {#wait-for-message-handlers} @@ -536,9 +556,11 @@ Use [`Workflow::await()`](https://php.temporal.io/classes/Temporal-Workflow.html ```php #[WorkflowInterface] -class MyWorkflow { +class MyWorkflow +{ #[WorkflowMethod] - public function run() { + public function run() + { // ... yield Workflow::await(fn() => Workflow::allHandlersFinished()); return "workflow-result"; @@ -551,7 +573,8 @@ You can silence these warnings on a per-handler basis by passing the `unfinished ```php #[UpdateMethod(unfinishedPolicy: HandlerUnfinishedPolicy::Abandon)] - public function myUpdate() { + public function myUpdate() + { // ... } ``` From e127c0362efed10fa172dc1e186377cee39fdaac Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Wed, 13 Nov 2024 14:17:35 +0400 Subject: [PATCH 06/13] Describe a part of message handler troubleshooting --- docs/develop/php/message-passing.mdx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index 54a457fd7f..b93e35fbdd 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -645,3 +645,28 @@ class MyWorkflow }); } ``` + +## Message handler troubleshooting {#message-handler-troubleshooting} + +When sending a Signal, Update, or Query to a Workflow, your Client might encounter the following errors: + +- **The client can't contact the server**: + You'll receive a [`ServiceClientException`](https://php.temporal.io/classes/Temporal-Exception-Client-ServiceClientException.html) in case of a server connection error. + [How to configure RPC Retry Policy](/develop/php/temporal-clients#configure-rpc-retry-policy) + +- **RPC timout**: + You'll receive a [`TimeoutException`](https://php.temporal.io/classes/Temporal-Exception-Client-TimeoutException.html) in case of an RPC timeout. + [How to configure RPC timeout](/develop/php/temporal-clients#configure-rpc-timeout) + +- **The workflow does not exist**: + You'll receive a [`WorkflowNotFoundException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowNotFoundException.html) exception. + +See [Exceptions in message handlers](/encyclopedia/workflow-message-passing#exceptions) for a nonโ€“PHP-specific discussion of this topic. + +### Problems when sending a Signal {#signal-problems} + +When using Signal, the only exception that will result from your requests during its execution is `ServiceClientException`. +All handlers may experience additional exceptions during the initial (pre-Worker) part of a handler request lifecycle. + +For Queries and Updates, the client waits for a response from the Worker. +If an issue occurs during the handler Execution by the Worker, the client may receive an exception. From bb5823b734053b9c7eb2704aef29b345d3dc356a Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Wed, 13 Nov 2024 14:38:52 +0400 Subject: [PATCH 07/13] Describe a part of problems when sending a Query --- docs/develop/php/message-passing.mdx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index b93e35fbdd..b2c3a7dfeb 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -670,3 +670,18 @@ All handlers may experience additional exceptions during the initial (pre-Worker For Queries and Updates, the client waits for a response from the Worker. If an issue occurs during the handler Execution by the Worker, the client may receive an exception. + +### Problems when sending a Query {#query-problems} + +When working with Queries, you may encounter these errors: + +- **There is no Workflow Worker polling the Task Queue**: +You'll receive a [`WorkflowNotFoundException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowNotFoundException.html). + +- **Query failed**: +You'll receive a [`WorkflowQueryException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowQueryException.html) if something goes wrong during a Query. +Any exception in a Query handler will trigger this error. +This differs from Signal and Update requests, where exceptions can lead to Workflow Task Failure instead. + +- **The handler caused the Workflow Task to fail.** +This would happen, for example, if the Query handler blocks the thread for too long without yielding. From 0f1112170813ed82d44591e3ea277bc976974cba Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Wed, 13 Nov 2024 14:45:06 +0400 Subject: [PATCH 08/13] Describe a part of problems when sending an Update --- docs/develop/php/message-passing.mdx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index b2c3a7dfeb..d4bb905ae0 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -671,6 +671,30 @@ All handlers may experience additional exceptions during the initial (pre-Worker For Queries and Updates, the client waits for a response from the Worker. If an issue occurs during the handler Execution by the Worker, the client may receive an exception. +### Problems when sending an Update {#update-problems} + +When working with Updates, you may encounter these errors: + +- **No Workflow Workers are polling the Task Queue**: +Your request will be retried by the SDK Client indefinitely. +You can [configure RPC timeout](/develop/php/temporal-clients#configure-rpc-timeout) to impose a timeout. +This raises a [`WorkflowUpdateRPCTimeoutOrCanceledException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowUpdateRPCTimeoutOrCanceledException.html). + +- **Update failed**: You'll receive a [`WorkflowUpdateException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowUpdateException.html) exception. +There are two ways this can happen: + + - The Update was rejected by an Update validator defined in the Workflow alongside the Update handler. + + - The Update failed after having been accepted. + +Update failures are like [Workflow failures](/references/failures#errors-in-workflows). +Issues that cause a Workflow failure in the main method also cause Update failures in the Update handler. +These might include: + + - A failed Child Workflow + - A failed Activity (if the Activity retries have been set to a finite number) + - The Workflow author raising `ApplicationFailure` + ### Problems when sending a Query {#query-problems} When working with Queries, you may encounter these errors: From 68aa02d1de89c7b0877bc061df676b9f5ae369af Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Wed, 13 Nov 2024 16:39:26 +0400 Subject: [PATCH 09/13] Add a part of problems when sending an Update --- docs/develop/php/message-passing.mdx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index d4bb905ae0..803d40dc4b 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -695,6 +695,13 @@ These might include: - A failed Activity (if the Activity retries have been set to a finite number) - The Workflow author raising `ApplicationFailure` +- **The handler caused the Workflow Task to fail**: +A [Workflow Task Failure](/references/failures#errors-in-workflows) causes the server to retry Workflow Tasks indefinitely. What happens to your Update request depends on its stage: + - If the request has been admitted by the server but not accepted or rejected by the Workflow, you receive a [`WorkflowUpdateResultException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowUpdateResultException.html). + - If the request has been rejected by the workflow, you receive a [`WorkflowUpdateException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowUpdateException.html). + - If the request has been accepted, it is durable. + Once the Workflow is healthy again after a code deploy, use an [`UpdateHandle`](https://php.temporal.io/classes/Temporal-Client-Update-UpdateHandle.html) to fetch the Update result. + ### Problems when sending a Query {#query-problems} When working with Queries, you may encounter these errors: From 1bf05592e0187e5a08790c611626ffc35b2a57ae Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Wed, 13 Nov 2024 17:04:11 +0400 Subject: [PATCH 10/13] Add a part of problems when sending an Update --- docs/develop/php/message-passing.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index 803d40dc4b..b6feb77a25 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -702,6 +702,14 @@ A [Workflow Task Failure](/references/failures#errors-in-workflows) causes the s - If the request has been accepted, it is durable. Once the Workflow is healthy again after a code deploy, use an [`UpdateHandle`](https://php.temporal.io/classes/Temporal-Client-Update-UpdateHandle.html) to fetch the Update result. +- **The Workflow finished while the Update handler execution was in progress**: +You'll receive a [`WorkflowUpdateException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowUpdateException.html). +This happens if the Workflow finished while the Update handler execution was in progress, for example because + + - The Workflow was canceled or failed. + + - The Workflow completed normally or continued-as-new and the Workflow author did not [wait for handlers to be finished](/encyclopedia/workflow-message-passing#finishing-message-handlers). + ### Problems when sending a Query {#query-problems} When working with Queries, you may encounter these errors: From 3a44c313da629df033a61203ab5a25649e468403 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Wed, 13 Nov 2024 17:12:01 +0400 Subject: [PATCH 11/13] Cleanup; update index --- docs/develop/php/index.mdx | 2 ++ docs/develop/php/message-passing.mdx | 9 +-------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/develop/php/index.mdx b/docs/develop/php/index.mdx index 4248410cc7..6550126a3d 100644 --- a/docs/develop/php/index.mdx +++ b/docs/develop/php/index.mdx @@ -54,6 +54,8 @@ Send messages to read the state of Workflow Executions. - [How to develop with Signals](/develop/php/message-passing#signals) - [How to develop with Queries](/develop/php/message-passing#queries) - [How to develop with Updates](/develop/php/message-passing#updates) +- [Message handler patterns](/develop/php/message-passing#message-handler-patterns) +- [Message handler troubleshooting](/develop/php/message-passing#message-handler-troubleshooting) ## [Interrupt a Workflow feature guide](/develop/php/cancellation) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index b6feb77a25..8b5df44b73 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -348,9 +348,7 @@ var_dump($workflow->getCurrentState()); Queries are sent from a Temporal Client. -## Updates {#updates} - -**How to develop with Updates using the Temporal PHP SDK** +## How to develop with Updates {#updates} An [Update](/encyclopedia/workflow-message-passing#sending-updates) is an operation that can mutate the state of a Workflow Execution and return a response. @@ -505,11 +503,6 @@ It doesn't apply to pure read operations, like Queries or Update Validators. For additional information, see [Inject work into the main Workflow](/encyclopedia/workflow-message-passing#injecting-work-into-main-workflow), [Ensuring your messages are processed exactly once](/encyclopedia/workflow-message-passing#exactly-once-message-processing), and [this sample](https://github.com/temporalio/samples-php/tree/master/app/src/SafeMessageHandlers) demonstrating safe `async` message handling. -::: - -### Add async handlers to use `await` {#async-handlers} - - ### Add wait conditions to block Sometimes, async Signal or Update handlers need to meet certain conditions before they should continue. From ef080fd125d0f01b3ae73167df0c70e7d9ba4075 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Fri, 15 Nov 2024 12:57:08 +0400 Subject: [PATCH 12/13] Remove mention of `WorkflowUpdateResultException` --- docs/develop/php/message-passing.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index 8b5df44b73..20efd394a1 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -690,8 +690,7 @@ These might include: - **The handler caused the Workflow Task to fail**: A [Workflow Task Failure](/references/failures#errors-in-workflows) causes the server to retry Workflow Tasks indefinitely. What happens to your Update request depends on its stage: - - If the request has been admitted by the server but not accepted or rejected by the Workflow, you receive a [`WorkflowUpdateResultException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowUpdateResultException.html). - - If the request has been rejected by the workflow, you receive a [`WorkflowUpdateException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowUpdateException.html). + - If the request hasn't been accepted by the server, you receive a [`WorkflowUpdateException`](https://php.temporal.io/classes/Temporal-Exception-Client-WorkflowUpdateException.html). - If the request has been accepted, it is durable. Once the Workflow is healthy again after a code deploy, use an [`UpdateHandle`](https://php.temporal.io/classes/Temporal-Client-Update-UpdateHandle.html) to fetch the Update result. From 5a6f422fcb4b7638c4c8879c057e6dd8bc109a4e Mon Sep 17 00:00:00 2001 From: Brian MacDonald Date: Thu, 5 Dec 2024 15:45:10 -0500 Subject: [PATCH 13/13] Update docs/develop/php/message-passing.mdx --- docs/develop/php/message-passing.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/develop/php/message-passing.mdx b/docs/develop/php/message-passing.mdx index 18537503c3..2c5df3e3c8 100644 --- a/docs/develop/php/message-passing.mdx +++ b/docs/develop/php/message-passing.mdx @@ -505,6 +505,7 @@ It doesn't apply to pure read operations, like Queries or Update Validators. :::tip For additional information, see [Inject work into the main Workflow](/encyclopedia/workflow-message-passing#injecting-work-into-main-workflow), [Ensuring your messages are processed exactly once](/encyclopedia/workflow-message-passing#exactly-once-message-processing), and [this sample](https://github.com/temporalio/samples-php/tree/master/app/src/SafeMessageHandlers) demonstrating safe `async` message handling. +::: ### Add wait conditions to block