Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Sdk Laravel Package

temporal/sdk

Temporal PHP SDK for building durable, scalable workflow orchestration with Temporal. Author Workflows and Activities in PHP, run them with RoadRunner workers, and manage executions via gRPC clients. Composer-installable with optional protobuf for performance.

View on GitHub
Deep Wiki
Context7
v2.17.1

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.17.0...v2.17.1

v2.17.0

Temporal PHP SDK v2.17.0

This release focuses on better observability, improved error handling, clearer APIs, and significantly enhanced testing & CI reliability. Several deprecations were introduced to improve long-term API consistency.


Features

Expose FirstRunId & OriginalRunId in WorkflowInfo

PR: https://github.com/temporalio/sdk-php/pull/691 Author: @xepozz

WorkflowInfo now exposes:

  • getFirstRunId()
  • getOriginalRunId()

This improves traceability across retries, resets and continue-as-new chains.

$info = Workflow::getInfo();

$firstRun = $info->getFirstRunId();
$originalRun = $info->getOriginalRunId();

This is particularly useful for observability tooling and debugging long-running workflow chains.


Workflow Current Details Support

PR: https://github.com/temporalio/sdk-php/pull/710 Author: @xepozz

Workflows can now expose structured “current details” metadata, improving runtime inspection and debugging of workflow state.


Expose Retry Policy in Activity Context

PR: https://github.com/temporalio/sdk-php/pull/656 Author: @roxblnfk

Activities can now access their configured retry policy:

$context = Activity::getContext();
$retryPolicy = $context->getRetryOptions();

This enables dynamic behavior depending on retry configuration.


ApplicationFailure ErrorCategory Exposure

PR: https://github.com/temporalio/sdk-php/pull/666 Author: @roxblnfk

ApplicationFailure now exposes ErrorCategory, allowing more precise error classification and handling logic in workflows.


RawValue Implementation

PR: https://github.com/temporalio/sdk-php/pull/683 Author: @xepozz

Introduced RawValue for pass-through or untyped payload handling. Useful when custom serialization control is required.


Environment Configuration Exposure

PR: https://github.com/temporalio/sdk-php/pull/661 Author: @roxblnfk

Improved environment configuration visibility and integration, especially useful for CI and containerized deployments.


Windows Test Runner Wrapper

PR: https://github.com/temporalio/sdk-php/pull/707 Author: @xepozz

Added a wrapper to properly handle non-zero exit codes on Windows systems. Improves cross-platform development and CI reliability.


Deprecations

Activity Method Without #[ActivityMethod] Attribute

PR: https://github.com/temporalio/sdk-php/pull/677 Author: @xepozz

Using an activity method without the required #[\Temporal\Activity\ActivityMethod] attribute now triggers a deprecation warning.

#[\Temporal\Activity\ActivityMethod]
public function sendEmail(): void
{
    // ...
}

This ensures explicit activity registration and prevents subtle misconfiguration.

[!TIP] You may disable this behavior with the feature flag \Temporal\Worker\FeatureFlags::$warnOnActivityMethodWithoutAttribute See https://github.com/temporalio/sdk-php/blob/962c897757d9e9c29d579edb12c94e01b1c6fd52/src/Worker/FeatureFlags.php#L66C25-L66C61


Improvements

Friendly Outbound Context Exception

PR: https://github.com/temporalio/sdk-php/pull/662 Author: @roxblnfk

Improved error messages when workflow/activity context is misused outside its valid execution scope. Exceptions are now more descriptive and actionable.


Improved DX for WorkflowRunInterface::getResult($type)

PR: https://github.com/temporalio/sdk-php/pull/678 Author: @xepozz

Improved typed result retrieval and clearer error feedback when incorrect types are requested.


DateInterval Ambiguity Warning

PR: https://github.com/temporalio/sdk-php/pull/663 Author: @roxblnfk

Improved handling and warnings for ambiguous DateInterval usage to avoid subtle time calculation inconsistencies.


Improved Priority Validation

PR: https://github.com/temporalio/sdk-php/pull/719 Author: @xepozz

Enhanced validation in Priority::withFairnessWeight() with stricter guarantees and additional test coverage.


More Lenient Search Attribute Parsing

PR: https://github.com/temporalio/sdk-php/pull/716 Author: @xepozz

Search attribute parsing is now more tolerant to slightly variant input types, improving robustness.


More Informative Error Messages

PR: https://github.com/temporalio/sdk-php/pull/679 Author: @xepozz

General improvement of error clarity across workflow and activity contexts.


Fixes

Correct Exception Types from Activity & Workflow Contexts

PR: https://github.com/temporalio/sdk-php/pull/687 Author: @xepozz

Ensures correct exception propagation and typing consistency.


Sync with Default PHP Timezone

PR: https://github.com/temporalio/sdk-php/pull/686 Author: @xepozz

Fixes mismatch between Temporal runtime behavior and PHP default timezone.


Fix PHP 8.4 Deprecations in Tests

PR: https://github.com/temporalio/sdk-php/pull/672 Author: @xepozz

Ensures forward compatibility with PHP 8.4.


Upgrade symfony/process Minimum Version

PR: https://github.com/temporalio/sdk-php/pull/706 Author: @xepozz

Minimum supported version bumped to 5.4.51.


CODEOWNERS Syntax Fix

PR: https://github.com/temporalio/sdk-php/pull/712 Author: @mjameswh (New contributor)


Testing & CI Improvements


Platform & Dependency Updates


Documentation


Full Changelog

https://github.com/temporalio/sdk-php/compare/v2.16.0...v2.17.0

v2.16.0

[!WARNING] RoadRunner 2025.1.3+ is required.

Abandoned Child Workflow Cancellation

Added a new feature flag FeatureFlags::$cancelAbandonedChildWorkflows to control the cancellation behavior of abandoned Child Workflows.

Previously, when a parent workflow was canceled, all child workflows would be canceled, including those with ParentClosePolicy::Abandon. This behavior was incorrect - abandoned child workflows should continue running independently when their parent is canceled.

# worker.php
use Temporal\Worker\FeatureFlags;

// Fixed behavior (does NOT cancel abandoned children) - recommended
FeatureFlags::$cancelAbandonedChildWorkflows = false;

// Default behavior (cancels abandoned children - matches previous SDK versions)
FeatureFlags::$cancelAbandonedChildWorkflows = true;

[!WARNING] When setting $cancelAbandonedChildWorkflows = false:

  • If you start an abandoned child workflow in the main workflow scope, it may miss the cancellation signal if you await only on the child workflow. Use Promise::race() with a timer to properly handle cancellation.
  • If you start an abandoned child workflow in an async scope that is later canceled, the child workflow will not be affected by the scope cancellation.
  • You can still cancel abandoned child workflows manually by calling WorkflowStubInterface::cancel().

New Promises

The PHP SDK now supports React Promise v3. To make this work correctly in the Workflow Worker environment, the promises have been forked and improved in the internal/promise package.

The fork addresses critical issues for long-running Workflow Workers: made rejection handler reusable (a v3 feature), removed exit(255) calls from rejection handling that would terminate the worker process, added declare(strict_types=1) throughout, and improved type annotations for better static analysis support.

A key improvement is the [@yield](https://github.com/yield) annotation added to PromiseInterface, which enables proper type inference when using promises with generators in Workflows. This annotation is recognized by IDEs (PHPStorm) and static analysis tools (Psalm), significantly improving DX:

interface SomeActivity {
    /**
     * [@return](https://github.com/return) \React\Promise\PromiseInterface<ResultDto> 
     */
    public function doSomething(int $value): ResultDto;
}

final class Workflow {
    public function handle(): \Generator
    {
        $activity = \Temporal\Workflow::newActivityStub(SomeActivity::class);
        $result = yield $activity->doSomething(42); // IDE and Psalm infer $result as ResultDto
    }
}

The SDK supports both React Promise v2 and v3 - the version used depends on what you require in your composer.json.

[!WARNING] React Promise v3 includes optimizations that may slightly change promise resolution order compared to v2. This could potentially affect Workflow determinism in edge cases.

If you experience issues after upgrading, lock to React Promise v2 in your composer.json:

{
    "require": {
        "react/promise": "^2.11"
    }
}

Destroyable Interface

Workflows can now implement the Destroyable interface from the internal/destroy package to explicitly manage resource cleanup when the Workflow instance is evicted from memory.

This is particularly useful when your Workflow contains circular references between objects that prevent PHP's garbage collector from properly cleaning up memory. While this is not a common scenario, having explicit control over resource cleanup is critical for long-running Workers handling many workflow executions.

The SDK automatically calls the destroy() method when a Workflow instance needs to be evicted from memory, allowing you to break circular references and release resources deterministically.

final class Workflow implements Destroyable
{
    /** Collection with cross-linked objects that also implements Destroyable */
    private LinkedCollection $collection;

    // ...

    public function destroy(): void
    {
        // Must be idempotent - safe to call multiple times
        $collection = $this->collection ?? null;
        unset($this->collection);
        $collection?->destroy();
    }
}

Enhanced Workflow Info

Added new fields to Workflow::getInfo():

  • Access the root Workflow execution from any Workflow in the execution chain, including deeply nested child Workflows.
  • Access the Workflow's retry policy directly from the Workflow Context.
$rootExecution = Workflow::getInfo()->rootExecution;
$retryOptions = Workflow::getInfo()->retryOptions;

RoadRunner PSR Logger

The RoadRunner ecosystem now includes a new roadrunner/psr-logger package that can be used with Temporal SDK.

By default, the SDK uses \Temporal\Worker\Logger\StderrLogger which outputs messages to STDERR. RoadRunner captures these messages and logs them at the INFO level.

The new \RoadRunner\PsrLogger\RpcLogger sends logs to RoadRunner via RPC with precise log levels and structured context data.

Get Started:

composer require roadrunner/psr-logger
use RoadRunner\PsrLogger\RpcLogger;
use Spiral\Goridge\RPC\RPC;
use Temporal\WorkerFactory;

$rpc = RPC::create('tcp://127.0.0.1:6001');
$logger = new RpcLogger($rpc);

$factory = WorkerFactory::create(logger: $logger);
$worker = $factory->newWorker('my-task-queue');

New Worker Versioning (experimental)

Worker Versioning enables safe deployment of workflow changes by controlling how Workflows move between different worker versions. Each worker deployment is identified by a unique Build ID, and workflows can be pinned to specific versions or automatically upgrade to the latest version.

Worker Configuration

Configure versioning when creating a worker:

use Temporal\Worker\WorkerOptions;
use Temporal\Worker\WorkerDeploymentOptions;
use Temporal\Common\Versioning\VersioningBehavior;

$worker = $factory->newWorker(
    'my-task-queue',
    WorkerOptions::new()
        ->withDeploymentOptions(
            WorkerDeploymentOptions::new()
                ->withUseVersioning(true)
                ->withVersion('build-v1.2.3')
                ->withDefaultVersioningBehavior(VersioningBehavior::Pinned)
        )
);

Workflow Versioning Behavior

Control versioning behavior per workflow using the #[WorkflowVersioningBehavior] attribute:

use Temporal\Workflow;
use Temporal\Common\Versioning\VersioningBehavior;

#[Workflow\WorkflowInterface]
class MyWorkflow
{
    #[Workflow\WorkflowMethod]
    #[Workflow\WorkflowVersioningBehavior(VersioningBehavior::Pinned)]
    public function handle(): \Generator
    {
        // Workflow will stay pinned to its original deployment version
        yield Workflow::timer(3600);
        return 'Done';
    }
}

Versioning Behaviors:

  • Pinned: Workflow stays on its original deployment version until completion
  • AutoUpgrade: Workflow automatically moves to the current deployment version on the next workflow task

Client Override

Override versioning behavior when starting a workflow:

use Temporal\Client\WorkflowOptions;
use Temporal\Common\Versioning\VersioningOverride;
use Temporal\Common\Versioning\WorkerDeploymentVersion;

// Pin to specific version
$workflow = $client->newWorkflowStub(
    MyWorkflow::class,
    WorkflowOptions::new()
        ->withVersioningOverride(
            VersioningOverride::pinned(
                WorkerDeploymentVersion::fromString('build-v1.2.3')
            )
        )
);

// Or enable auto-upgrade
$workflow = $client->newWorkflowStub(
    MyWorkflow::class,
    WorkflowOptions::new()
        ->withVersioningOverride(VersioningOverride::autoUpgrade())
);

[!NOTE] This feature is experimental and requires RoadRunner 2025.1.3+. See the Worker Versioning documentation for deployment strategies and best practices.

Priority Fairness (experimental)

Priority Fairness extends the Task Queue Priority feature with fairness keys and weights, enabling balanced task processing across multiple tenants or execution groups within a single task queue. This is particularly valuable for multi-tenant SaaS applications where you need to prevent large tenants from monopolizing worker resources.

Key Concepts:

  • Fairness Key: A short string (up to 64 bytes) that groups tasks together, typically representing a tenant ID or priority band (e.g., "premium", "standard", "free")
  • Fairness Weight: A float value (0.001 to 1000) that controls the relative processing share for each fairness key. Higher weights receive proportionally more throughput

The fairness mechanism ensures tasks are dispatched in proportion to their weights. For example, with 1000 tenants each having a weight of 1.0, each tenant receives roughly equal task processing throughput regardless of their individual workload size.

Setting Fairness Parameters:

use Temporal\Common\Priority;
use Temporal\Client\WorkflowOptions;

// Start workflow with fairness settings
$workflow = $workflowClient->newWorkflowStub(
    OrderWorkflow::class,
    WorkflowOptions::new()
        ->withTaskQueue('task-queue')
        ->withPriority(
            Priority::new()
                ->withFairnessKey('tenant-123')
                ->withFairnessWeight(2.5)
        ),
);

In Workflow Context:

use Temporal\Workflow;
use Temporal\Common\Priority;

// Set fairness for an Activity
$activity = Workflow::newActivityStub(
    ActivityInterface::class,
    ActivityOptions::new()
        ->withScheduleToCloseTimeout('5 minutes')
        ->withPriority(
            Priority::new()
                ->withFairnessKey('premium-tenant')
                ->withFairnessWeight(10.0)
        ),
);

// Set fairness for a Child Workflow
$childWorkflow = Workflow::newChildWorkflowStub(
    ChildWorkflowInterface::class,
    ChildWorkflowOptions::new()
        ->withPriority(
            Priority::new()
                ->withFairnessKey('tenant-456')
                ->withFairnessWeight(1.0)
        ),
);

Accessing Fairness Information:

// In Workflow
$priority = Workflow::getInfo()->priority;
$fairnessKey = $priority->fairnessKey;
$fairnessWeight = $priority->fairnessWeight;

// In Activity
$priority = Activity::getInfo()->priority;
$fairnessKey = $priority->fairnessKey;
$fairnessWeight = $priority->fairnessWeight;

Weight Precedence:

Fairness weights can be configured from multiple sources, with the following precedence (highest to lowest):

  1. Task queue configuration overrides (set via API)
  2. Weight attached to workflow/activity in code
  3. Default weight of 1.0

[!NOTE]

  • Weight values are automatically clamped to the range [0.001, 1000]
  • Fairness keys are inherited by child workflows and activities by default
  • The fairness mechanism works in conjunction with priority keys for fine-grained control
  • Watch the Temporal Task Queue Fairness | Multi-Tenant Workflows Made Easy video for more details

DestructMemorizedInstanceException (experimental)

Added a new feature flag FeatureFlags::$throwDestructMemorizedInstanceException to control an internal memory cleanup mechanism.

When enabled (default), the SDK throws DestructMemorizedInstanceException into pending promises during Workflow eviction. This exception may occasionally surface in user code where it should be ignored - which is not obvious and adds complexity.

# worker.php
use Temporal\Worker\FeatureFlags;

// Default behavior
FeatureFlags::$throwDestructMemorizedInstanceException = true;

// Experimental - disable exception throwing
FeatureFlags::$throwDestructMemorizedInstanceException = false;

[!WARNING] You can experiment with disabling this flag in non-production environments to monitor memory usage. Future SDK versions will move away from this mechanism toward promise implementations that self-cleanup without exceptions.

Pull Requests

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.15.0...v2.16.0

v2.15.1

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.15.0...v2.15.1

v2.15.0

[!WARNING] RoadRunner 2025.1.2 is required.

Task Queue Priority

Task Queue Priority allows you to control the execution order of workflows, activities, and child workflows based on assigned priority values within a single task queue. You can select a priority level in the integer range 1...5. A lower value implies higher priority. The default priority if unspecified is in the middle of the range, 3.

[!NOTE] As this feature is currently in Pre-release stage, it is not intended for production use at this time. See product release stages for more information.

Pre-requisites

  • If using Temporal Cloud, please contact Temporal support or your Temporal account team to enable this feature for your cloud namespace(s).
  • If self-hosting Temporal, use the latest pre-release development server and set matching.useNewMatcher dynamic config on the relevant task queues (or namespaces).

Client API

# New Priority DTO
$priority = Priority::new(priorityKey: 1);

# Set Priority on a Workflow
$workflow = $workflowClient->newWorkflowStub(
    OrderWorkflowInterface::class,
    WorkflowOptions::new()
        ->withTaskQueue('task-queue')
        ->withPriority($priority),
);

Workflow API

# New Priority DTO
$priority = Priority::new(priorityKey: 1);

# Set Priority on an Activity
$activity = Workflow::newActivityStub(
    ActivityInterface::class,
    ActivityOptions::new()
        ->withTaskQueue('task-queue')
        ->withStartToCloseTimeout('5 minutes')
        ->withPriority($priority),
);

# Set Priority on a Child Workflow
$childWorkflow = Workflow::newChildWorkflowStub(
    ChildWorkflowInterface::class,
    ChildWorkflowOptions::new()
        ->withTaskQueue('task-queue')
        ->withPriority($priority),
);

Get Priority value in Workflow or Activity

// Get
$priority = Activity::getInfo()->priority;
$priority = Workflow::getInfo()->priority;

[!NOTE]

  • Lower numbers = higher priority.
  • Tasks with the same priority are scheduled in FIFO order.
  • If priority is unsupported by the server, these settings are silently ignored.
  • Remember this feature is not production ready at this stage.

User Metadata

Handler Descriptions

You can now add descriptions to Query, Signal, and Update handlers. Descriptions are available through the description parameter in QueryMethod, SignalMethod, and UpdateMethod attributes, as well as in the Workflow::registerSignal(), Workflow::registerQuery(), and Workflow::registerUpdate() methods. These descriptions will be displayed in the Temporal UI for better handler documentation.

Using Attributes:

#[QueryMethod('get_counter', description: 'Get the current counter value')]
public function getCounter(): int
{
    return $this->counter;
}

#[SignalMethod('inc_counter', description: 'Increment the counter value')]
public function incCounter(): void
{
    ++$this->counter;
}

Using Registration Methods:

Workflow::registerQuery('get_counter', $this->getCounter(...), 'Get the current counter value');
Workflow::registerSignal('increment_counter', $this->incrementCounter(...), 'Increment the counter value');

Activity and Timer Summaries

You can now add custom metadata summaries to Activity and Timer executions. These summaries will be displayed in the Workflow history within the Temporal UI, providing better visibility into workflow execution details.

Activity Summary:

yield Workflow::executeActivity(
    type: 'activity_type',
    options: ActivityOptions::new()
        ->withScheduleToCloseTimeout(30)
        ->withSummary('Process user payment'),
);

Timer Summary:

yield Workflow::timer(
    interval: 30,
    options: TimerOptions::new()->withSummary('Wait for external service response'),
);

Activity Pause

When a heartbeating activity is paused, an ActivityPausedException will be thrown. Added Activity::getCancellationDetails() that returns ActivityCancellationDetails DTO that provides the reasons for the activity's cancellation.

Pull Requests

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.14.1...v2.15.0

v2.14.0

[!WARNING] RoadRunner 2024.3.3+ is required.

Workflow Logger

Logging is a critical component for monitoring and troubleshooting your Temporal applications. The PHP SDK now provides a dedicated logger for use within Workflows that respects replay semantics and adds contextual information automatically.

To get a PSR-3 compatible logger in your Workflow code, use the Workflow::getLogger() method:

use Temporal\Workflow;

#[Workflow\WorkflowInterface]
class MyWorkflow
{
    #[Workflow\WorkflowMethod]
    public function execute(string $param): \Generator
    {
        Workflow::getLogger()->info('Workflow started', ['parameter' => $param]);

        // Your workflow implementation

        Workflow::getLogger()->info('Workflow completed');
        return 'Done';
    }
}

Replay Mode Behavior

An important feature of the Workflow logger is its replay-aware behavior. By default, logs are only emitted during the initial Workflow execution and are suppressed during replay to prevent duplicate log entries.

If you want to enable logging during replay (for debugging purposes), you can configure this with the enableLoggingInReplay option:

$factory = WorkerFactory::create();
$worker = $factory->newWorker('your-task-queue', WorkerOptions::new()
    ->withEnableLoggingInReplay(true)
);

Automatic Context Enrichment

The Workflow logger automatically enriches log entries with the current task queue information. Every log message will include a task_queue key in its context, making it easier to filter and correlate logs.

For example, if a log statement is:

$logger->info('Processing order', ['order_id' => 123]);

The actual logged context will be:

{ "task_queue": "your-task-queue", "order_id": 123 }

This happens automatically without any additional configuration.

Default Logger

By default, the PHP SDK uses a StderrLogger that outputs log messages to the standard error stream. These messages are automatically captured by RoadRunner and incorporated into its logging system with the INFO level, ensuring proper log collection in both development and production environments. For more details on RoadRunner's logging capabilities, see the RoadRunner Logger documentation.

Using a Custom Logger

You can configure your Temporal worker to use a custom PSR-3 compatible logger implementation:

$myLogger = new MyLogger();

$workerFactory = WorkerFactory::create(converter: $converter);
$worker = $workerFactory->newWorker(
    taskQueue: 'my-task-queue',
    logger: $myLogger,
);

Your custom logger will be used throughout the Temporal SDK, including for Workflow logging when accessed through Workflow::getLogger().

getInstance() in Context

Added Activity::getInstance() and Workflow::getInstance() methods to get the current Activity and Workflow instances.

Changed workflow execution flow:

  • First, the Workflow is initialized. The __construct() method is called.
    • If the #[WorkflowInit] attribute is present, the handler's arguments are resolved and passed to the constructor.
    • There you can't make calls to start Activity, ChildWorkflow, Timer, etc.
  • WorkflowInboundCallInterceptor::execute() is called
    • Arguments from the previous step are used, but they can be overridden for the handler call.
    • You can call Activity, ChildWorkflow, Timer, etc.
    • Workflow::getInstance() returns the initialized Workflow instance.
    • Now errors from this step are recorded in the Workflow history.
  • Workflow Handler is called.

Dynamic Handlers

Added methods to define dynamic handlers for Signals, Updates, and Queries that will be called if a handler for a specific name is not found.

// Dynamic Query Handler
\Temporal\Workflow::registerDynamicQuery(function (string $name, ValuesInterface $arguments): string {
    return \sprintf(
        'Got query `%s` with %d arguments',
        $name,
        $arguments->count(),
    );
});

// Dynamic Update Handler
\Temporal\Workflow::registerDynamicUpdate(
    static fn(string $name, ValuesInterface $arguments): string => \sprintf(
        'Got update `%s` with %d arguments',
        $name,
        $arguments->count(),
    ),
    static fn(string $name, ValuesInterface $arguments) => \str_starts_with(
        $name,
        'update_',
    ) or throw new \InvalidArgumentException('Invalid update name'),
);

User Metadata Support in Client API

Added support for user metadata in Workflow Start/Schedule methods, improving the ability to attach additional information to workflow executions.

  • Added ExecutionConfig with UserMetadata in Workflow Description
  • Added support for user metadata in Workflow Start/Schedule methods. Metadata in Timers and Activities require changes in RoadRunner and can be added in the future.

Client API

use Temporal\Client\GRPC\ServiceClient;
use Temporal\Client\ScheduleClient;
use Temporal\Client\Schedule\Action\StartWorkflowAction;
use Temporal\Client\WorkflowClient;
use Temporal\Client\WorkflowOptions;

$serviceClient = ServiceClient::create('127.0.0.1:7233');

// Start Workflow with user metadata
$workflowClient = WorkflowClient::create($serviceClient);
$stub = $workflowClient->newUntypedWorkflowStub(
    'SimpleWorkflow',
    (new WorkflowOptions())
        ->withStaticSummary('some text')
        ->withStaticDetails('details') 
);
$workflowClient->start($stub);

// Describe workflow
echo $stub->describe()->config->userMetadata->summary;
echo $stub->describe()->config->userMetadata->details;

// Schedule Workflow with user metadata
$scheduleClient = ScheduleClient::create($serviceClient);
$schedule = $scheduleClient->createSchedule(
    \Temporal\Client\Schedule\Schedule::new()
        ->withAction(StartWorkflowAction::new(SimpleWorkflow::class)
            ->withStaticSummary('some-summary')
            ->withStaticDetails('some-details'))
);

// Describe schedule
$action = $schedule->describe()->schedule->action;
assert($action instanceof StartWorkflowAction);

echo $action->userMetadata->details;
echo $action->userMetadata->summary;

Workflow context:

$stub = \Temporal\Workflow::newChildWorkflowStub(
    SimpleWorkflow::class,
    (new Workflow\ChildWorkflowOptions())
        ->withStaticSummary('some text')
        ->withStaticDetails('details')
);

Additional Improvements

  • Skip magic methods in Activity classes: Magic methods not marked by the ActivityMethod attribute will not be registered as activity methods
  • Enhanced Workflow description info: Added new fields into Workflow stub -> describe result:
    • rootExecution
    • firstRunId
    • executionDuration

Pull requests

  • Features:
    • Expose Activity and Workflow instance from context by @roxblnfk in #593
    • Add methods to register fallback handlers by @roxblnfk in #581
    • Add Workflow Logger by @roxblnfk in #589
    • Skip magic methods in Activity classes by @roxblnfk in #572
    • Update Workflow description info by @roxblnfk in #578
    • Support UserMetadata in Client API by @roxblnfk in #585
  • SDK Hotfixes:
    • Fix incorrect updateWithStart signature by @DanielsStugis in #594
    • Fix collecting Workflow requests after destroying by @roxblnfk in #599
    • Fix polling in UpdateHandle::fetchResult() by @roxblnfk in #591
  • Maintenance

New Contributors

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.13.0...v2.14.0

v2.13.4

What's changed

  • Fixed memory leak on upsert Memo / Search Attributes / Typed Search Attributes by @roxblnfk in #590

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.13.3...v2.13.4

v2.13.3

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.13.2...v2.13.3

v2.13.2

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.13.1...v2.13.2

v2.13.1

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.13.0...v2.13.1

v2.13.0

[!WARNING] RoadRunner 2024.3.3 is required.

Search Attributes

A new approach for working with Search Attributes has been implemented - Typed Search Attributes. For this, new methods have been added to WorkflowOptions DTO and Workflow facade.

$keyDestinationTime = SearchAttributeKey::forDatetime('DestinationTime');
$keyOrderId = SearchAttributeKey::forKeyword('OrderId');

$workflow = $workflowClient->newWorkflowStub(
    OrderWorkflowInterface::class,
    WorkflowOptions::new()
        ->withWorkflowExecutionTimeout('10 minutes')
        ->withTypedSearchAttributes(
            TypedSearchAttributes::empty()
                ->withValue($keyOrderId, $orderid)
                ->withValue($keyDestinationTime, new \DateTimeImmutable('2028-11-05T00:10:07Z'))
        ),
);

#[Workflow\WorkflowInterface]
class OrderWorkflowInterface {
    // ...

    #[Workflow\UpdateMethod]
    public function postponeDestinationTime(\DateInterval $interval)
    {
        // Get keys to work with
        $keyDestinationTime = SearchAttributeKey::forDatetime('DestinationTime');
        $keyToRemove = SearchAttributeKey::forKeyword('SomeFieldToRemove');

        /** [@var](https://github.com/var) DateTimeImmutable $destinationTime */
        $destinationTime = Workflow::getInfo()->typedSearchAttributes->get($keyDestinationTime);

        Workflow::upsertTypedSearchAttributes(
            $keyDestinationTime->valueSet($destinationTime->add($interval)),
            $keyToRemove->valueUnset(),
        );
    }
}

When starting the Temporal Dev Server, you can specify types for Search Attributes.

$testEnv->startTemporalServer(searchAttributes: [
    'testBool' => ValueType::Bool,
    'testInt' => ValueType::Int,
    'testFloat' => ValueType::Float,
    'testString' => ValueType::String,
    'testKeyword' => ValueType::Keyword,
    'testKeywordList' => ValueType::KeywordList,
    'testDatetime' => ValueType::Datetime,
]);

Workflow Init

The new #[WorkflowInit] attribute has been added for the Workflow class constructor This attribute allows you to receive arguments in the constructor that were passed when the Workflow was started. The Workflow input arguments are also passed to your #[WorkflowMethod] method -- that always happens, whether or not you use the #[WorkflowInit] attribute. This is useful if you have message handlers that need access to Workflow input: see Initializing the Workflow first.

use Temporal\Workflow;

#[Workflow\WorkflowInterface]
class GreetingExample
{
    private readonly string $nameWithTitle;
    private bool $titleHasBeenChecked;

    // Note the attribute is on a public constructor
    #[Workflow\WorkflowInit]
    public function __construct(string $input)
    {
        $this->nameWithTitle = 'Sir ' . $input;
        $this->titleHasBeenChecked = false;
    }

    #[Workflow\WorkflowMethod]
    public function getGreeting(string $input)
    {
        yield Workflow::await(fn() => $this->titleHasBeenChecked);
        return "Hello " . $this->nameWithTitle;
    }

    #[Workflow\UpdateMethod]
    public function checkTitleValidity()
    {
        // 👉 The handler is now guaranteed to see the workflow input
        // after it has been processed by the constructor.
        $isValid = yield Workflow::executeActivity('activity.checkTitleValidity', [$this->nameWithTitle]);
        $this->titleHasBeenChecked = true;
        return $isValid;
    }
}

[!WARNING] By default, the Workflow Handler runs before Signals and Updates in PHP SDK v2. This behavior is incorrect. To avoid breaking already written Workflows, since PHP SDK v2.11.0, a feature flag was added to enhance the behavior of the Workflow Handler. Make sure to set this flag to true to enable the correct behavior.

Memo

Added a method to update the Workflow's Memo Workflow::upsertMemo.

Workflow::upsertMemo([
    'key1' => 'foo',
    'key2' => 42,
    'key3' => ['subkey1' => 'value']
    'key4' => null, // remove key4
});

MetaStorm metadata

To improve Developer Experience, metadata for the MetaStorm plugin has been added. If you use MetaStorm, the IDE will now suggest Workflow classes and types in the corresponding methods.

image

Pull Requests

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.12.3...v2.13.0

v2.12.3

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.12.2...v2.12.3

v2.12.2

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.12.1...v2.12.2

v2.12.1

What's Changed

New Contributors

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.12.0...v2.12.1

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.

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: https://github.com/temporalio/sdk-php/compare/v2.11.3...v2.12.0

v2.11.4

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.11.3...v2.11.4

v2.11.3

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.11.2...v2.11.3

v2.11.2
v2.11.1

What's Changed

New Contributors

Full Changelog: https://github.com/temporalio/sdk-php/compare/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 of TimeoutException in Update cases.
  • Exposed the new WorkflowStub::getUpdateHandle() method that returns UpdateHandle by UpdateId:
    $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 get UpdateContext that contains UpdateId.

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

Pull Requests

New Contributors

Full Changelog: https://github.com/temporalio/sdk-php/compare/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: https://github.com/temporalio/sdk-php/compare/v2.10.2...v2.10.3

v2.10.2

What's Changed

  • Fix client connection timeout by @roxblnfk in #445
  • Tests: add more coroutine tests by @roxblnfk in #444

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.10.1...v2.10.2

v2.10.1

What's Changed

  • Fix Payloads failing decoding in case when an external Temporal SDK returns empty payload that doesn't contain even a NULL value by @wolfy-j in #442
  • Fix a Workflow hang in cases where a non-promise value is yielded by @roxblnfk in #443

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.10.0...v2.10.1

v2.10.0

What's Changed

  • Convert Policy Constants to Enums by @roxblnfk in #438
  • Add a new parameter $lifecycleStage into Update\UpdateOptions::new() by @roxblnfk in #439

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.9.2...v2.10.0

v2.9.2

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.9.1...v2.9.2

v2.9.1

What's Changed

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.9.0...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](https://github.com/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](https://github.com/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](https://github.com/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](https://github.com/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](https://github.com/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](https://github.com/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](https://github.com/psalm-immutable) attribute has been removed from all interceptor interfaces.
  • Fixed SystemInfoInterceptor constructor parameter: ConnectionInterface instead of ServiceClient.
  • In SystemInfoInterceptor, new features related to caching Server Capabilities inside the Connection are considered.
  • ServiceClient::setServerCapabilities() method has been removed from the ServiceClientInterface. 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 and Workflow\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: https://github.com/temporalio/sdk-php/compare/v2.8.3...v2.9.0

v2.8.3

What's Changed

  • Fixed DateInterval to protobuf Duration conversion by @Zylius in #424

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.8.2...v2.8.3

v2.8.2

What's Changed

  • Remove experimental flag from StartDelay by @tlalfano in #409
  • Fix JSON interval unmarshalling via DurationJsonType::parse() fix by @Zylius in #412
  • Add GH action to generate API documentation by @msmakouz in #407

New Contributors

Full Changelog: https://github.com/temporalio/sdk-php/compare/v2.8.1...v2.8.2

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed