Hello, Temporal community! We are glad to announce the release of the Temporal PHP SDK v2.6.0.
Some changes are related to RoadRunner 2023, which has not yet been released at the time of the SDK release. However, you can download the pre-release version of RoadRunner 2023.3 and try out the new features right now.
vendor/bin/rr get --stability=RC
ReactPHP Promise v3
The ReactPHP Promise dependency has been updated from version 2 to version 3.
Note
There are no BC breaks in the Temporal SDK, but there are BC breaks in the ReactPHP Promise library. If you rely on the functions of the ReactPHP Promise library and use them directly, please familiarize yourself with the list of changes there. We have not completely abandoned compatibility with Promise v2, and it will be available for some time — just add "react/promise": "^2.9" in your composer.json, if you are tied to promise v2.
Despite the fact that some functions (some(), map(), reduce()) have been removed from React, they have remained in our Temporal\Promise helper with the same behavior.
Either way, welcome the new features:
- the new convenient methods of
PromiseInterface:catch()andfinally(); @templateannotation for thePromiseInterface, which allows you to specify the type of the promise result.
So start specifying types in Activity and Workflow, and when this initiative is implemented, the Workflow code will become fully typed and understandable for IDE and static analysis.
#[\Temporal\Activity]
class MyActivityClass {
/**
* @return PromiseInterface
*/
#[\Temporal\ActivityMethod('MyWorkflow')]
public function myActivityMethod(): string {
return 'some string';
}
}
#[\Temporal\Workflow]
class MyWorkflowClass {
#[\Temporal\WorkflowMethod]
public function handle() {
$activity = \Temporal\Workflow::newActivityStub(MyActivityClass::class);
// IDE will know that the $uuid is a UuidInterface instance
$uuid = yield \Temporal\Workflow::uuid();
// IDE will know that the $result is a string
$result = yield $activity->myActivityMethod();
}
}
#[\Temporal\Activity]
class MyActivityClass {
/**
* @return PromiseInterface
*/
#[\Temporal\ActivityMethod('MyWorkflow')]
public function myActivityMethod(): string {
return 'some string';
}
}
#[\Temporal\Workflow]
class MyWorkflowClass {
#[\Temporal\WorkflowMethod]
public function handle() {
$activity = \Temporal\Workflow::newActivityStub(MyActivityClass::class);
// IDE will know that the $uuid is a UuidInterface instance
$uuid = yield \Temporal\Workflow::uuid();
// IDE will know that the $result is a string
$result = yield $activity->myActivityMethod();
}
}
UUID support
The ramsey/uuid package is now a dependency of the PHP SDK and is supported at many levels:
- In the Marshaller: use the `UuidInterface type in object properties – it will automatically be serialized and deserialized through a string representation.
- In the DataConverter: specify
UuidInterfacein the method parameters of Workflow and Activity – this will work, in the returned types or ingetResult().
This also applies toSideEffect.
Added new methods:
Eager start
Eager Workflow Dispatch is a mechanism that minimizes the duration from starting a workflow to the processing of the first workflow task, making Temporal more suitable for latency sensitive applications.
Eager Workflow Dispatch can be enabled if the server supports it and a local worker is available, the task is fed directly to the worker.
Note
That this will require some extra work to allocate a workflow slot on a Temporal worker on the same task queue and delivering a workflow task to the workflow from the StartWorfklowExecutionResponse.
Returning array of objects
Added the possibility to return a list of objects from activity/workflow.
/** @var \Temporal\Client\WorkflowClientInterface $workflowClient */
/** @var \Temporal\Internal\Workflow\ActivityStub $activity */
//When executing workflow:
/** @var Message[] $result */
$result = $workflowClient->start($workflow, 'John')->getResult(Type::arrayOf(Message::class));
//When executing activity within a workflow:
/** @var Message[] $result */
$result = yield $activity->execute(
name: 'myActivity',
args: [$input],
returnType: Type::arrayOf(Message::class),
);
History length
Now you don’t need to guess how many events your code produces to decide if it’s time to call continue-as-new. Just check Workflow::getInfo()->historyLength property. This field will be updated with any response from the RoadRunner server.
Available since RoadRunner 2023.2.
Visibility: listWorkflowExecutions and listWorkflowExecutions
Added WorkflowClient::listWorkflowExecutions() and WorkflowClient::countWorkflowExecutions() methods that can help to get a list of workflow executions using a list filter query syntax. As a result, a Paginator object is returned which can be used in a simple way:
/** @var \Temporal\Client\WorkflowClientInterface $client */
$paginator = $client->listWorkflowExecutions(
query: "WorkflowType='MyWorkflow' and StartTime between '2022-08-22T15:04:05+00:00' and '2023-08-22T15:04:05+00:00'",
namespace: 'default',
);
// Iterate all items (pages will be fetched automatically)
foreach ($paginator as $execution) {
// ...
}
// Get current page items
$items = $paginator->getPageItems();
// Get next page
$nextPage = $paginator->getNextPage();
// Get items count (an RPC method will be called that may require a preconfigured advanced Visibility)
$count = $paginator->count();
Documentation about Visibility: https://docs.temporal.io/visibility
Replay API
PR: https://github.com/temporalio/sdk-php/pull/336
Replay API is very useful tool for a workflow determinism testing. It recreates the exact state of a Workflow Execution. You can replay a Workflow from the beginning of its Event History. Replay succeeds only if the Workflow Definition is compatible with the provided history from a deterministic point of view.
Examples
/**
* We assume you already have a WorkflowClient instance in the scope.
* @var \Temporal\Client\WorkflowClientInterface $workflowClient
*/
// Find all workflow executions of type "MyWorkflow" and task queue "MyTaskQueue".
$executions = $workflowClient->listWorkflowExecutions(
"WorkflowType='MyWorkflow' AND TaskQueue='MyTaskQueue'"
);
$replayer = new \Temporal\Testing\Replay\WorkflowReplayer();
// Replay each workflow execution.
foreach ($executions as $executionInfo) {
try {
$replayer->replayFromServer(
workflowType: $executionInfo->type->name,
execution: $executionInfo->execution,
);
} catch (\Temporal\Testing\Replay\Exception\ReplayerException $e) {
// Handle the replay error.
}
}
$history = $this->workflowClient->getWorkflowHistory(
execution: $run->getExecution(),
)->getHistory();
(new WorkflowReplayer())->replayHistory($history);
To store a History JSON file, use the \Temporal\Testing\Replay\WorkflowReplayer::downloadHistory() method.
Available since RoadRunner 2023.3



