Releases: temporalio/sdk-php
v2.11.2
v2.11.1
What's Changed
- Fix hierarchical Workflow classes processing by @roxblnfk in #513
- Fix SearchAttributes in ChildWorkflow by @roxblnfk in #515
- Fix typo in
hasExecution
docstring by @jmortlock in #519 - Fix: use environment options to create RoadRunnerActivityInvocationCache by @jmortlock in #520
New Contributors
- @jmortlock made their first contribution in #519
Full Changelog: v2.11.0...v2.11.1
v2.11.0
Worker
Feature Flags
Since version 2.11.0, the SDK has introduced feature flags that allow you to change the behavior of the SDK at the level of the entire PHP worker (process).
They are introduced for a consistent migration to more correct behavior, which will be established in the next major version or earlier.
To set a feature flag, you need to use the Temporal\Worker\FeatureFlags
class in the beginning of your worker script:
use Temporal\Worker\FeatureFlags;
// Include the Composer autoloader
require __DIR__ . '/vendor/autoload.php';
// Set the feature flags
FeatureFlags::$workflowDeferredHandlerStart = true;
FeatureFlags::$warnOnWorkflowUnfinishedHandlers = true;
Signal with start
An important fix was made in the SDK: previously, if a Workflow was started with a Signal, the Workflow method would begin execution first.
This happened because the initialization of the Workflow method generator would start executing the generator code up to the first yield
.
However, this behavior does not meet expectations: Signals should start first, followed by the Workflow method.
Since this change may break backward compatibility, it has been hidden behind a Feature Flag Temporal\Worker\FeatureFlags::$workflowDeferredHandlerStart
.
Warn about unfinished handlers
Added logging of unfinished Signal and Update handlers when a Workflow finishes.
Logging is performed using the error_log()
function and by default is output to stderr
.
The flag responsible for this behavior is Temporal\Worker\FeatureFlags::$warnOnWorkflowUnfinishedHandlers
, which is also disabled by default.
It is recommended to enable this flag and assess its impact on your application, as this behavior is likely to be enabled by default in future SDK versions.
Additionally, if unfinished handlers are not an error, you can individually set the $unfinishedPolicy
option in the corresponding attribute
#[Workflow\WorkflowInterface]
interface MyWorkflow
{
#[Workflow\WorkflowMethod]
public function run();
#[Workflow\SignalMethod(unfinishedPolicy: HandlerUnfinishedPolicy::Abandon)]
public function mySignal(): void;
#[Workflow\UpdateMethod(unfinishedPolicy: HandlerUnfinishedPolicy::Abandon)]
public function myUpdate(): void;
}
To determine if all handlers have finished, you can use the new method Workflow::allHandlersFinished()
:
#[Workflow\WorkflowMethod]
public function handler()
{
// ...
// Wait for all handlers to finish
yield Workflow::await(
static fn() => Workflow::allHandlersFinished(),
);
}
Workflow Update
Common
Client:
- Added
WorkflowUpdateRPCTimeoutOrCanceledException
that will be thrown instead ofTimeoutException
in Update cases. - Exposed the new
WorkflowStub::getUpdateHandle()
method that returnsUpdateHandle
byUpdateId
:$stub = $workflowClient->newUntypedRunningWorkflowStub($wfId, $wfRunId, $wfType); $handle = $stub->getUpdateHandle($updateId); $handle->getResult(5);
Worker:
- Now
ExceptionInterceptor
is used to detect that exception is error that breaks task or failure that fails update. - Using the new method
Workflow::getUpdateContext()
, you can getUpdateContext
that containsUpdateId
.
Register Update handler dynamically
Previously, only Signal and Query handlers could be registered in a Workflow dynamically. Now, this is also possible for Update handlers.
The method Workflow::registerUpdate()
allows passing a validator along with the handler:
// Workflow scope
Workflow::registerUpdate(
'my-update',
fn(Task $task) => $this->queue->push($task),
fn(Task $task) => $this->isValidTask($task) or throw new \InvalidArgumentException('Invalid task'),
);
Schedule Update with Search Attributes
A new way to update Schedule via callback, similar to other SDKs, has been added.
The method ScheduleHandle::update()
accepts a closure that takes ScheduleUpdateInput
and returns ScheduleUpdate
.
ScheduleUpdateInput
is generated on the SDK side along with the describe()
method call.
Updating Schedule via callback allows modifying Search Attributes:
$handle->update(
fn (ScheduleUpdateInput $input): ScheduleUpdate => ScheduleUpdate::new($input->description->schedule)
->withSearchAttributes(
$input->description->searchAttributes
->withValue('foo', 'bar'),
->withValue('bar', 42),
);
);
Other changes
- Added getter for
ActivityPrototype::$factory
by @Nyholm in #492 - Updated
WorkerOptions
by @roxblnfk in #489 - Exposed
ShouldContinueAsNew
andHistorySize
by @roxblnfk in #475Workflow::getInfo()->historySize; Workflow::getInfo()->shouldContinueAsNew;
Pull Requests
- Divide errors and failures in updates by @roxblnfk in #473
- Update dependencies by @roxblnfk in #474
- Add acceptance tests by @roxblnfk in #482
- Expose UpdateId in interceptors and workflow scope by @roxblnfk in #477
- Expose ShouldContinueAsNew and HistorySize by @roxblnfk in #475
- Expose
WorkflowStub::getUpdateHandle
by @roxblnfk in #484 - Start Workflow Method after Signal if it's' signalWithStart by @roxblnfk in #483
- Expose
Workflow::allHandlersFinished()
by @roxblnfk in #486 - Remove final from WorkflowInterface by @Nyholm in #487
- Update WorkerOptions by @roxblnfk in #489
- Add WorkflowUpdateRPCTimeoutOrCanceledException by @roxblnfk in #490
- Warn about unfinished handlers by @roxblnfk in #488
- Remove unused and invalid use statement by @Nyholm in #493
- Add getter for ActivityPrototype::$factory by @Nyholm in #492
- Register Update handler dynamically by @roxblnfk in #500
- Schedule update with Search Attributes by @roxblnfk in #504
- Actualize CS Fixer config, update CI by @roxblnfk in #506
- Move FeatureFlags class into Worker namespace by @roxblnfk in #510
- Expose next retry delay on Application Failure by @roxblnfk in #511
New Contributors
Full Changelog: v2.10.3...v2.11.0
v2.10.3
What's Changed
- Fix Child Workflow Task Queue Inheritance by @roxblnfk in #452
- Fix EncodedValues to return null if possible when there is no value in Payloads by @roxblnfk in #467
- Fix default Data Converters set to be able to decode binary/protobuf messages by @roxblnfk in #468
- Fix empty scheduled workflow id by @roxblnfk in #469
- Fix signaling for child workflow when it was continued as new by @roxblnfk in #470
- Fix TaskQueue inheritance when workflow is continued as new by @roxblnfk in #471
Full Changelog: v2.10.2...v2.10.3
v2.10.2
v2.10.1
v2.10.0
v2.9.2
v2.9.1
v2.9.0
Connection Management Layer
Issue #224
In the Service Client, a method getConnection()
has been added, which returns a ConnectionInterface
.
ConnectionInterface
includes public methods isConnected()
, disconnect()
, connect(float $timeout)
, allowing
control over the connection to the Temporal server.
A gRPC connection is lazy in PHP and is established only when the first gRPC method is called.
Using the connect()
method, users can immediately establish and verify connection credentials without the need for gRPC method calls.
Users can sequentially call connect()
and disconnect()
without causing errors related to closed gRPC channels, as the channels are recreated under the hood.
/** @var \Temporal\Client\WorkflowClient $workflowClient */
// Establish a connection with the server.
// An exception will be thrown if the connection is not established within 5 seconds.
$workflowClient->getServiceClient()->getConnection()->connect(5);
Server Capabilities info now is cached in the Connection object and will be updated on each reconnect.
/** @var \Temporal\Client\WorkflowClient $workflowClient */
// Establish a connection with the server and call getSystemInfo() RPC method.
$capabilities = $workflowClient->getServiceClient()->getServerCapabilities();
if (!$capabilities?->supportsSchedules) } {
throw new \Temporal\Exception\TemporalException('Server does not support schedules');
}
Service Client with Secure Connection
A deprecation error will now be triggered when a ServiceClient
is created directly through the constructor. Static factories are the only recommended way to create a ServiceClient
.
One of such static methods has changes:
in ServiceClient::createSSL()
, the root certificate parameter has been made optional because it should be skipped when connecting to the Temporal Cloud.
All keys can be passed as a string payload (previously, only by file name was allowed). If the provided file cannot be read, a clear exception will be thrown.
Service Client with API auth key
The ClientService now can accept an API key for authentication.
$serviceClient = \Temporal\Client\GRPC\ServiceClient::createSSL(
'temporal.my-project.com:7233',
__DIR__ . '/my-project.key',
__DIR__ . '/my-project.crt',
)->withAuthKey($key); // $key is a string or a \Stringable object
$workflowClient = new \Temporal\Client\WorkflowClient($serviceClient);
You may pass your own Stringable
implementation as the $key argument to be able to change the key dynamically.
New methods for all the Clients (Workflow and Schedule)
Issue #338
Added new methods to WorkflowClient, ScheduleClient and ScheduleHandle:
withTimeout(float $timeout)
withDeadline()
withRetryOptions()
withMetadata()
They may be used before calling any method that sends a gRPC request to the server.
/** @var \Temporal\Client\ScheduleClient $scheduleClient */
$list = $scheduleClient->withTimeout(5)->listSchedules();
All the new methods are immutable and return a new instance of the client that will use the same connection as the original client, but with the specified timeout, deadline or retry options.
/** @var \Temporal\Client\WorkflowClient $workflowClient */
// All the calls $workflow->* will be executed with a 5-second timeout.
$workflow = $workflowClient->withTimeout(5)->newWorkflowStub(MyWorkflow::class);
// Will be called with a 10-second timeout.
$workflowClient->withTimeout(10)->start($workflow, 'foo', 'bar')
// Will be called with a 5-second timeout because the stub was created with a 5-second timeout client.
$workflow->signal();
Note: WorkflowClientInterface
and ScheduleClientInterface
have been updated with the new methods.
RPC Retry Policy
Issue #421
Client RPC requests have a new algorithm for calculating the timeout until the next retry attempt:
- Added Jitter, which introduces a random variation to the calculated time (default is 10%).
- InitialInterval has been changed from 500ms to 50ms. For the
RESOURCE_EXHAUSTED
error, the interval is 1000ms.
All settings are configurable:
$workflowClient->withRetryOptions(
\Temporal\Client\Common\RpcRetryOptions::new()
->withInitialInterval('500 milliseconds')
->withCongestionInitialInterval('5 seconds')
->withMaximumInterval('5 minutes')
->withBackoffCoefficient(5)
->withMaximumAttempts(4)
->withJitter(0.25)
);
Namespace Inheritance in Client methods
A mistake was made in the implementation of several client functions last time: instead of using the Namespace value from ClientOptions, a parameter with the default value "default" was used.
This complicates the use of Temporal Cloud, where user's Namespace differs from "default".
Affected methods are:
WorkflowClient::listWorkflowExecutions()
WorkflowClient::countWorkflowExecutions()
WorkflowClient::getWorkflowHistory()
ScheduleClient::getHandle()
ScheduleClient::listSchedules()
The $namespace
parameter is now null
by default. If a method receives null
, the Namespace from ClientOptions will be used.
Describe a Workflow
Use the API to obtain comprehensive information about a started Workflow.
$stub = $workflowClient->newWorkflowStub(SimpleWorkflow::class);
$run = $workflowClient->start($stub, 'Hello World!');
/** @var WorkflowExecutionDescription $description */
$description = $run->describe();
You can use the Workflow Describe feature to get the status of a running Workflow.
$stub = $workflowClient->newUntypedRunningWorkflowStub($wfId);
/** @var WorkflowExecutionStatus $status */
$status = $stub->describe()->info->status;
Other changes
- Fixed Namespace inheritance when a Child Workflow is started (#415)
- Added enum
WorkflowIdConflictPolicy
that can be passed to WorkflowOptions in the client API (#417) - The
@psalm-immutable
attribute has been removed from all interceptor interfaces. - Fixed
SystemInfoInterceptor
constructor parameter:ConnectionInterface
instead ofServiceClient
. - In
SystemInfoInterceptor
, new features related to caching Server Capabilities inside the Connection are considered. ServiceClient::setServerCapabilities()
method has been removed from theServiceClientInterface
. The implementing method just triggers a deprecation error.ServiceClient::getServerCapabilities()
method now loads the Server Capabilities from the Connection object instead of just returning the cached value.- Updated
ServerCapabilities
DTO: added all the new fields; the flags are available as public properties. - Move
Temporal\Client\WorkflowExecutionHistory
,Workflow\Client\CountWorkflowExecutions
,Workflow\Client\Paginator
andWorkflow\Client\ServerCapabilities
into other namespaces. WorkerVersionStamp::$bundleId
is deprecated now (#417)- Update description for WorkflowStubInterface::startUpdate() method (#429)
Pull requests
- Client improvements by @roxblnfk in #411
- Expose API to describe Workflow by @roxblnfk in #414
- Inherit Namespace from the parent Workflow in a Child Workflow by @roxblnfk in #415
- Expose API key client option by @roxblnfk in #418
- Expose WorkflowIdConflictPolicy by @roxblnfk in #417
- Add RpcRetryOption and use longer retry interval on RESOURCE_EXHAUSTED by @roxblnfk in #425
- Update description for WorkflowStubInterface::startUpdate() method by @roxblnfk in #429
- Use namespace from the Service Client in ScheduleClient::listSchedules() by @roxblnfk in #430
Full Changelog: v2.8.3...v2.9.0