Releases: temporalio/sdk-php
v2.6.1
v2.6.0
What's Changed
- Add supporting for React/Promises v3 by @roxblnfk in #351
- Friendly version of
listWorkflowExecutions
by @roxblnfk in #324 - Eager Workflow start client option by @roxblnfk in #355
- Use internal run_id for each request from RoadRunner by @roxblnfk in #340
- Expose Replayer API by @roxblnfk in #336
- feat: allow to return array of objects by @seregazhuk in #259
- Possibility to use different types for result of activity for
Wokflow::executeActivity
by @cv65kr in #319 - Wrapper for multiple task queues by @cv65kr in #263
- Fix CI badge in readme by @roxblnfk in #332
- Add API to count workflows by @roxblnfk in #333
- Add
messageType
header to protobuf payloads by @roxblnfk in #337, #339 - Apply changes from 2.7.0 related with HistoryLength to 2.6.0 by @roxblnfk in #341
- Adding RoadRunner Version Checker by @msmakouz in #343
- Implement UUID conversion by @msmakouz in #321
- Better UUID support (passing without nesting) by @roxblnfk in #349
- Add
Workflow::uuid()
|uuid4()
|uuid7()
methods by @roxblnfk in #354 - [CI] Add Windows tests by @roxblnfk in #299
Full Changelog: v2.5.4...v2.6.0
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 yourcomposer.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()
; @template
annotation 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<non-empty-string>
*/
#[\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
UuidInterface
in the method parameters of Workflow and Activity - this will work, in the returned types or ingetResult()
.
This also applies toSideEffect
.
Added new methods:
$uuid = yield \Temporal\Workflow::uuid(); // Generate a UUID (if you don't care about the UUID version)
$uuid4 = yield \Temporal\Workflow::uuid4(); // Generate a UUID v4
$uuid7 = yield \Temporal\Workflow::uuid7(); // Generate a UUID v7
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.
/** @var \Temporal\Client\WorkflowClientInterface $workflowClient */
$workflow = $workflowClient->newWorkflowStub(
SimpleWorkflow::class,
\Temporal\Client\WorkflowOptions::new()
->withEagerStart() // <=
);
$workflowClient->start($workflow, 'hello');
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.0 (stable).
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: #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
To replay Workflow Executions, use the \Temporal\Testing\Replay\WorkflowReplayer
class.
In the following example, Event Histories are downloaded from the server, and then replayed. Note that this requires Advanced Visibility to be enabled.
/**
* 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.
}
}
You can download a workflow history manually from Temporal UI or using PHP, and then replay it from a memorized History object:
$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
Stability improvements
We have introduced a new way of identifying workflow operations. It's internal run_id, that helps to avoid
bugs related with async operations between Temporal, RoadRunner and SDK.
There will be no any "Got the response to undefined request" errors!
Available since RoadRunner 2023.3
Info:
If you want to install the pre-release version of RoadRunner 2023.3, then execute the command:vendor/bin/rr get --stability=RC
v2.5.4
v2.5.3
v2.5.2
What's Changed
- Fix
stdClass
unmarshalling by @roxblnfk in #327 - Fix PHP 8.2 types unmarshalling (
null
,false
,true
) by @roxblnfk in #329 - Provide the PHP-SDK version to RoadRunner and Temporal Server by @roxblnfk in #326
- Add Semgrep scanning by @jackdawm in #310
New Contributors
Full Changelog: v2.5.1...v2.5.2
v2.5.1
v2.5.0
What's Changed
- PHP Attributes: replace
implements NamedArgumentConstructorAttribute
with the attributeNamedArgumentConstructor
by @msmakouz in #292
That required for a better compatibility with the doctrine/annotations v2 - Update PHP RoadRunner packages versions by @roxblnfk in #297
New major versions was of the packages are related to the new RoadRunner 2023.1 release - Expand list of retryable gRPC errors by @roxblnfk in #298
Note: in the case when a Temporal server is unavailable and by the reason a Client call can't be completed, it might retry infinitely without a limited retry gRPC call policy. - Add supporting for
UndefinedResponse
command by @roxblnfk in #300
The command will be sent instead of logic exception throwing. The command is available since RoadRunner 2023.1
Full Changelog: v2.4.1...v2.5.0
v2.4.1
What's Changed
- Fix mapping for the
Memo
field in #290
It fixes two problems:- the problem where
WorkflowInfo
doesnt retrieve the correct info when usingWorker::getInfo()
; - the problem where
Workflow::getInfo()->searchableAttributes
isnull
.
- the problem where
Full Changelog: v2.4.0...v2.4.1
v2.4.0
What's Changed
- Marshaller upgrade by @roxblnfk and @zlodes in #278, #284, #275 (see below)
- The default value of Activity's
taskQueue
was changed from"default"
tonull
by @ruscon in #270 - An error will be passed into activity finalizer if it happens during activity execution by @seregazhuk in #267
- Testing and CI fixes:
Marshaller upgrade
- The
#[Marshal]
attribute now has the$nullable
parameter. You don't need to use theNullableType::class
value
as the$type
argument inside the#[Marshal]
attribute.Note:
#[MarshallArray]
has different default value for the$nullable
parameter.
That was made to prevent incompatible behavior (see #245). - The
#[Marshal]
attribute can be nested. You can put another#[Marshal]
attribute as the$to
argument for
NullableType
andArrayType
. ArrayType
can now processiterable
type automatically.EnumType
added by default in the type list by default for PHP >=8.1.ObjectType
:- now supports DTOs with
readonly
fields; - can process nested objects. Nested objects can have
#[Marshal]
attributes.
- now supports DTOs with
DateTimeType
now supports mutable and immutable DateTime types:- in a
DateTimeImmutable
property aDateTimeImmutable
object will be unmarshalled; - in a
DateTime
property aDateTime
object will be unmarshalled; - in a
Carbon\CarbonImmutable
property aCarbon\CarbonImmutable
object will be unmarshalled; - in a
DateTimeInterface
orCarbon\Carbon
property aCarbon\Carbon
object will be unmarshalled; - to change default behavior you can pass to the
#[Marshal]
attribute the needed class name as the$of
argument.
- in a
Changes and deprecations:
- The method
ObjectType::instance()
has been marked as deprecated. - Marshaller will throw a detailed exception about invalid argument value during unmarshalling.
-
Warning: marshalling rules that was got from the
#[Marshal]
attribute now are stricter than before.
All attributed properties with nullable type will be not nullable by default (excluding#[ArrayType]
).
In the case when thenull
value is passed, an exception will be thrown.
In this case you just need to remove the#[Marshal]
attribute or set the$nullable
parameter totrue
.
Full Changelog: v2.3.2...v2.4.0