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