Skip to content

Releases: temporalio/sdk-php

v2.6.1

04 Oct 20:05
v2.6.1
e5b375f
Compare
Choose a tag to compare

What's Changed

  • Remove react/promise v3 from composer.json. By @roxblnfk in #358 (issue #357)
  • Add tests in which a Workflow operates incorrectly if react/promise v3 is installed. By @roxblnfk in #359

Full Changelog: v2.6.0...v2.6.1

v2.6.0

15 Sep 17:11
v2.6.0
3bbdb70
Compare
Choose a tag to compare

What's Changed

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 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() and finally();
  • @template annotation for the PromiseInterface, 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 in getResult().
    This also applies to SideEffect.

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

28 Jul 15:24
v2.5.4
f3e2a6e
Compare
Choose a tag to compare

What's Changed

  • Fix potential issue when signal coroutine won't trigger await due to failed activity call by @wolfy-j in #335

Full Changelog: v2.5.3...v2.5.4

v2.5.3

21 Jul 17:25
v2.5.3
42b6f9e
Compare
Choose a tag to compare

What's Changed

  • Fix marshalling/unmarshalling of nullable object type by @roxblnfk in #334
  • Fix exceptions propagation from Signal methods. Only arguments decoding exceptions will be ignored, all other exceptions will be propagated. By @roxblnfk in #331

Full Changelog: v2.5.0...v2.5.3

v2.5.2

10 Jul 13:39
v2.5.2
ea20d36
Compare
Choose a tag to compare

What's Changed

New Contributors

Full Changelog: v2.5.1...v2.5.2

v2.5.1

31 May 21:15
v2.5.1
6c85e88
Compare
Choose a tag to compare

What's Changed

  • Fix deprecated string interpolation - replace ${var} with {$var}. By @roxblnfk in #309

Full Changelog: v2.5.0...v2.5.1

v2.5.0

18 Apr 09:39
v2.5.0
479b0b4
Compare
Choose a tag to compare

What's Changed

  • PHP Attributes: replace implements NamedArgumentConstructorAttribute with the attribute NamedArgumentConstructor 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

09 Mar 09:07
v2.4.1
17ef494
Compare
Choose a tag to compare

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 using Worker::getInfo();
    • the problem where Workflow::getInfo()->searchableAttributes is null.

Full Changelog: v2.4.0...v2.4.1

v2.4.0

02 Feb 13:46
v2.4.0
1f5d61c
Compare
Choose a tag to compare

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" to null 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 the NullableType::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 and ArrayType.
  • ArrayType can now process iterable 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.
  • DateTimeType now supports mutable and immutable DateTime types:
    • in a DateTimeImmutable property a DateTimeImmutable object will be unmarshalled;
    • in a DateTime property a DateTime object will be unmarshalled;
    • in a Carbon\CarbonImmutable property a Carbon\CarbonImmutable object will be unmarshalled;
    • in a DateTimeInterface or Carbon\Carbon property a Carbon\Carbon object will be unmarshalled;
    • to change default behavior you can pass to the #[Marshal] attribute the needed class name as the $of argument.

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 the null value is passed, an exception will be thrown.
    In this case you just need to remove the #[Marshal] attribute or set the $nullable parameter to true.

Full Changelog: v2.3.2...v2.4.0

v2.3.2

19 Dec 15:44
1a95df8
Compare
Choose a tag to compare

What's Changed

  • Fixed memory leak in the case when an uncompleted workflow with an active internal timer (see awaitWithTimeout) is destroyed by @roxblnfk in #268

Full Changelog: v2.3.1...v2.3.2