Releases: temporalio/sdk-php
v2.12.0
Mutex
Added new class Mutex
that provides a deterministic mechanism for concurrency control within Workflow.
It can be used within Signals, Updates, and the main Workflow handlers.
Added method Workflow::runLocked(Mutex $mutex, callable $callable): PromiseInterface
to execute a function in a locked context.
An explanation (click to expand)
use Temporal\Workflow;
#[Workflow\WorkflowInterface]
class TestWorkflow
{
#[Workflow\WorkflowMethod]
public function handle(): \Generator
{
$mutex = new Workflow\Mutex();
// Wait for the Mutex to be unlocked
yield $mutex;
assert(false === $mutex->isLocked(), 'The Mutex is unlocked here');
// Try to lock the Mutex, returns true if the Mutex was successfully locked
assert(true === $mutex->tryLock());
// Try to lock the Mutex again, returns false because the Mutex is already locked
assert(false === $mutex->tryLock());
// We may use it in Workflow::await() and Workflow::awaitWithTimeout() like a condition.
// It means wait until the Mutex is unlocked or timeout.
yield Workflow::awaitWithTimeout('5 seconds', $mutex);
assert(true === $mutex->isLocked(), 'The Mutex is still locked here because of the timeout');
$mutex->unlock(); // Unlock for the next test
// Get the mutex locked state and unlock it after the function is finished.
// The function will be executed asynchronously, so we can use `yield` inside to wait for the result.
// We don't need to control the Mutex manually, it will be locked and unlocked automatically.
yield Workflow::runLocked($mutex, static function () {
// Mutex is locked here
yield Workflow::timer('1 second');
// Mutex is still locked here
});
assert(false === $mutex->isLocked(), 'Mutex is unlocked here');
// In this example, we run 5 functions in parallel, but only one function can be executed at a time.
// When the first function is finished, the next function will be executed.
// All functions will be executed in the order they were added.
yield \Temporal\Promise::all([
Workflow::runLocked($mutex, $this->doSomething()),
Workflow::runLocked($mutex, $this->doSomething()),
Workflow::runLocked($mutex, $this->doSomething()),
Workflow::runLocked($mutex, $this->doSomething()),
Workflow::runLocked($mutex, $this->doSomething()),
]);
// Additionally, you can cancel the Promise returned by `runLocked` to interrupt or discard the function.
$promise = Workflow::runLocked($mutex, $this->doSomethingSomeTime());
$promise->cancel();
}
}
You can also check the related example in the php-samples repository.
UpdateWithStart
Added WorkflowClientInterface::updateWithStart()
that starts a new Workflow execution, runs an update function, and returns UpdateHandle
.
If the specified workflow execution is not running, then a new workflow execution is started and the update is sent in the first workflow task.
Alternatively if the specified workflow execution is running then, if the WorkflowIDConflictPolicy
is UseExisting
, the update is issued against the specified workflow, and if the WorkflowIDConflictPolicy
is Fail
, an error is returned.
The call will block until the update has reached the LifecycleStage
in the UpdateOptions
. Note that this means that the call will not return successfully until the update has been delivered to a worker.
Note: the feature is experimental, and the flag enableExecuteMultiOperation
might be required to be set to true
in the Temporal server configuration.
BTW startWithSignal()
is deprecated now, added signalWithStart()
Worker options
Added a new class ServiceCredentials
that allows you to set the ApiKey
for the RoadRunner worker.
Readme update
The README file of the repository has been updated. Many useful links and notes have been added.
Pull Requests
- Add Mutex by @roxblnfk in #499
- Extend interceptors context DTOs by @roxblnfk in #528
- Expose
UpdateWithStart
by @roxblnfk in #536 - Expose
query
parameter for Schedule list by @roxblnfk in #538 - Send
ApiKey
to RoadRunner with WorkerInfo by @roxblnfk in #539 - Parameters for test server by @cv65kr in #527
- Update readme by @roxblnfk in #540
Full Changelog: v2.11.3...v2.12.0
v2.11.4
v2.11.3
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