Skip to content

Commit

Permalink
Merge pull request #536: updateWithStart
Browse files Browse the repository at this point in the history
  • Loading branch information
roxblnfk authored Dec 17, 2024
2 parents 70311a7 + 0f0ceec commit 001cfe1
Show file tree
Hide file tree
Showing 34 changed files with 802 additions and 135 deletions.
24 changes: 24 additions & 0 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
<file src="src/Client/WorkflowClient.php">
<ArgumentTypeCoercion>
<code><![CDATA[$counter]]></code>
<code><![CDATA[$signal]]></code>
<code><![CDATA[$workflowType]]></code>
<code><![CDATA[$workflowType]]></code>
</ArgumentTypeCoercion>
Expand All @@ -148,13 +149,24 @@
<LessSpecificReturnStatement>
<code><![CDATA[new self($serviceClient, $options, $converter, $interceptorProvider)]]></code>
</LessSpecificReturnStatement>
<MissingParamType>
<code><![CDATA[$workflow]]></code>
</MissingParamType>
<MoreSpecificReturnType>
<code><![CDATA[static]]></code>
</MoreSpecificReturnType>
<RedundantFunctionCall>
<code><![CDATA[\sprintf]]></code>
<code><![CDATA[\sprintf]]></code>
</RedundantFunctionCall>
<TypeDoesNotContainType>
<code><![CDATA[$signal === '']]></code>
</TypeDoesNotContainType>
</file>
<file src="src/Client/WorkflowClientInterface.php">
<MissingParamType>
<code><![CDATA[$workflow]]></code>
</MissingParamType>
</file>
<file src="src/Client/WorkflowOptions.php">
<ImpureMethodCall>
Expand Down Expand Up @@ -384,6 +396,14 @@
</MissingParamType>
</file>
<file src="src/Internal/Client/WorkflowStarter.php">
<InvalidArgument>
<code><![CDATA[0]]></code>
<code><![CDATA[1]]></code>
<code><![CDATA[1]]></code>
</InvalidArgument>
<MissingTemplateParam>
<code><![CDATA[$fails]]></code>
</MissingTemplateParam>
<PossiblyNullArgument>
<code><![CDATA[$options->retryOptions ? $options->retryOptions->toWorkflowRetryPolicy() : null]]></code>
<code><![CDATA[$options->toMemo($this->converter)]]></code>
Expand All @@ -395,6 +415,9 @@
<RedundantConditionGivenDocblockType>
<code><![CDATA[$delay !== null]]></code>
</RedundantConditionGivenDocblockType>
<UndefinedInterfaceMethod>
<code><![CDATA[toHeader]]></code>
</UndefinedInterfaceMethod>
</file>
<file src="src/Internal/Client/WorkflowStub.php">
<PossiblyInvalidArgument>
Expand All @@ -405,6 +428,7 @@
<code><![CDATA[$attr->getFailure()]]></code>
<code><![CDATA[$attr->getResult()]]></code>
<code><![CDATA[$input->workflowType]]></code>
<code><![CDATA[$input->workflowType]]></code>
<code><![CDATA[$result->getQueryResult()]]></code>
<code><![CDATA[$this->execution]]></code>
<code><![CDATA[$this->execution]]></code>
Expand Down
5 changes: 4 additions & 1 deletion src/Client/Common/ServerCapabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ final class ServerCapabilities
* it in history
* @param bool $countGroupByExecutionStatus
* True if the server supports count group by execution status
* (-- api-linter: core::0140::prepositions=disabled --)
* @param bool $nexus
* True if the server supports Nexus operations.
* This flag is dependent both on server version and for Nexus to be enabled via server configuration.
*/
public function __construct(
public readonly bool $signalAndQueryHeader = false,
Expand All @@ -56,6 +58,7 @@ public function __construct(
public readonly bool $eagerWorkflowStart = false,
public readonly bool $sdkMetadata = false,
public readonly bool $countGroupByExecutionStatus = false,
public readonly bool $nexus = false,
) {}

/**
Expand Down
1 change: 1 addition & 0 deletions src/Client/GRPC/BaseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public function getServerCapabilities(): ?ServerCapabilities
eagerWorkflowStart: $capabilities->getEagerWorkflowStart(),
sdkMetadata: $capabilities->getSdkMetadata(),
countGroupByExecutionStatus: $capabilities->getCountGroupByExecutionStatus(),
nexus: $capabilities->getNexus(),
);
} catch (ServiceClientException $e) {
if ($e->getCode() === StatusCode::UNIMPLEMENTED) {
Expand Down
59 changes: 57 additions & 2 deletions src/Client/GRPC/ServiceClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,29 @@ public function StartWorkflowExecution(V1\StartWorkflowExecutionRequest $arg, ?C
return $this->invoke("StartWorkflowExecution", $arg, $ctx);
}

/**
* ExecuteMultiOperation executes multiple operations within a single workflow.
*
* Operations are started atomically, meaning if *any* operation fails to be
* started, none are,
* and the request fails. Upon start, the API returns only when *all* operations
* have a response.
*
* Upon failure, it returns `MultiOperationExecutionFailure` where the status code
* equals the status code of the *first* operation that failed to be started.
*
* NOTE: Experimental API.
*
* @param V1\ExecuteMultiOperationRequest $arg
* @param ContextInterface|null $ctx
* @return V1\ExecuteMultiOperationResponse
* @throws ServiceClientException
*/
public function ExecuteMultiOperation(V1\ExecuteMultiOperationRequest $arg, ?ContextInterface $ctx = null): V1\ExecuteMultiOperationResponse
{
return $this->invoke("ExecuteMultiOperation", $arg, $ctx);
}

/**
* GetWorkflowExecutionHistory returns the history of specified workflow execution.
* Fails with
Expand Down Expand Up @@ -777,8 +800,40 @@ public function GetWorkerBuildIdCompatibility(V1\GetWorkerBuildIdCompatibilityRe
}

/**
* Allows updating the Build ID assignment and redirect rules for a given Task
* Queue.
* Use this API to manage Worker Versioning Rules for a given Task Queue. There are
* two types of
* rules: Build ID Assignment rules and Compatible Build ID Redirect rules.
*
* Assignment rules determine how to assign new executions to a Build IDs. Their
* primary
* use case is to specify the latest Build ID but they have powerful features for
* gradual rollout
* of a new Build ID.
*
* Once a workflow execution is assigned to a Build ID and it completes its first
* Workflow Task,
* the workflow stays on the assigned Build ID regardless of changes in assignment
* rules. This
* eliminates the need for compatibility between versions when you only care about
* using the new
* version for new workflows and let existing workflows finish in their own
* version.
*
* Activities, Child Workflows and Continue-as-New executions have the option to
* inherit the
* Build ID of their parent/previous workflow or use the latest assignment rules to
* independently
* select a Build ID.
*
* Redirect rules should only be used when you want to move workflows and
* activities assigned to
* one Build ID (source) to another compatible Build ID (target). You are
* responsible to make sure
* the target Build ID of a redirect rule is able to process event histories made
* by the source
* Build ID by using [Patching](https://docs.temporal.io/workflows#patching) or
* other means.
*
* WARNING: Worker Versioning is not yet stable and the API and behavior may change
* incompatibly.
* (-- api-linter: core::0127::http-annotation=disabled
Expand Down
55 changes: 53 additions & 2 deletions src/Client/GRPC/ServiceClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,25 @@ public function DeprecateNamespace(V1\DeprecateNamespaceRequest $arg, ContextInt
* @throws ServiceClientException
*/
public function StartWorkflowExecution(V1\StartWorkflowExecutionRequest $arg, ContextInterface $ctx = null) : V1\StartWorkflowExecutionResponse;
/**
* ExecuteMultiOperation executes multiple operations within a single workflow.
*
* Operations are started atomically, meaning if *any* operation fails to be
* started, none are,
* and the request fails. Upon start, the API returns only when *all* operations
* have a response.
*
* Upon failure, it returns `MultiOperationExecutionFailure` where the status code
* equals the status code of the *first* operation that failed to be started.
*
* NOTE: Experimental API.
*
* @param V1\ExecuteMultiOperationRequest $arg
* @param ContextInterface|null $ctx
* @return V1\ExecuteMultiOperationResponse
* @throws ServiceClientException
*/
public function ExecuteMultiOperation(V1\ExecuteMultiOperationRequest $arg, ContextInterface $ctx = null) : V1\ExecuteMultiOperationResponse;
/**
* GetWorkflowExecutionHistory returns the history of specified workflow execution.
* Fails with
Expand Down Expand Up @@ -731,8 +750,40 @@ public function UpdateWorkerBuildIdCompatibility(V1\UpdateWorkerBuildIdCompatibi
*/
public function GetWorkerBuildIdCompatibility(V1\GetWorkerBuildIdCompatibilityRequest $arg, ContextInterface $ctx = null) : V1\GetWorkerBuildIdCompatibilityResponse;
/**
* Allows updating the Build ID assignment and redirect rules for a given Task
* Queue.
* Use this API to manage Worker Versioning Rules for a given Task Queue. There are
* two types of
* rules: Build ID Assignment rules and Compatible Build ID Redirect rules.
*
* Assignment rules determine how to assign new executions to a Build IDs. Their
* primary
* use case is to specify the latest Build ID but they have powerful features for
* gradual rollout
* of a new Build ID.
*
* Once a workflow execution is assigned to a Build ID and it completes its first
* Workflow Task,
* the workflow stays on the assigned Build ID regardless of changes in assignment
* rules. This
* eliminates the need for compatibility between versions when you only care about
* using the new
* version for new workflows and let existing workflows finish in their own
* version.
*
* Activities, Child Workflows and Continue-as-New executions have the option to
* inherit the
* Build ID of their parent/previous workflow or use the latest assignment rules to
* independently
* select a Build ID.
*
* Redirect rules should only be used when you want to move workflows and
* activities assigned to
* one Build ID (source) to another compatible Build ID (target). You are
* responsible to make sure
* the target Build ID of a redirect rule is able to process event histories made
* by the source
* Build ID by using [Patching](https://docs.temporal.io/workflows#patching) or
* other means.
*
* WARNING: Worker Versioning is not yet stable and the API and behavior may change
* incompatibly.
* (-- api-linter: core::0127::http-annotation=disabled
Expand Down
53 changes: 49 additions & 4 deletions src/Client/WorkflowClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Temporal\Client;

use Doctrine\Common\Annotations\Reader;
use JetBrains\PhpStorm\Deprecated;
use Spiral\Attributes\AnnotationReader;
use Spiral\Attributes\AttributeReader;
use Spiral\Attributes\Composite\SelectiveReader;
Expand All @@ -24,6 +25,9 @@
use Temporal\Client\Common\ClientContextTrait;
use Temporal\Client\Common\Paginator;
use Temporal\Client\GRPC\ServiceClientInterface;
use Temporal\Client\Update\LifecycleStage;
use Temporal\Client\Update\UpdateHandle;
use Temporal\Client\Update\UpdateOptions;
use Temporal\Client\Workflow\CountWorkflowExecutions;
use Temporal\Client\Workflow\WorkflowExecutionHistory;
use Temporal\DataConverter\DataConverter;
Expand Down Expand Up @@ -144,10 +148,7 @@ public function start($workflow, ...$args): WorkflowRunInterface
);
}

/**
* @param object|WorkflowStubInterface $workflow
*/
public function startWithSignal(
public function signalWithStart(
$workflow,
string $signal,
array $signalArgs = [],
Expand Down Expand Up @@ -205,6 +206,50 @@ public function startWithSignal(
);
}

#[Deprecated(replacement: '%class%->signalWithStart(%parametersList%)')]
public function startWithSignal(
$workflow,
string $signal,
array $signalArgs = [],
array $startArgs = [],
): WorkflowRunInterface {
return $this->signalWithStart($workflow, $signal, $signalArgs, $startArgs);
}

public function updateWithStart(
$workflow,
string|UpdateOptions $update,
array $updateArgs = [],
array $startArgs = [],
): UpdateHandle {
$workflow instanceof WorkflowProxy && !$workflow->hasHandler() && throw new InvalidArgumentException(
'Unable to start workflow without workflow handler',
);

$update = \is_string($update) ? UpdateOptions::new($update, LifecycleStage::StageAccepted) : $update;

$workflowStub = WorkflowStubConverter::fromWorkflow($workflow);

$workflowType = $workflowStub->getWorkflowType() ?? throw new InvalidArgumentException(
'Unable to start untyped workflow without given workflowType',
);
$workflowStub->hasExecution() and throw new InvalidArgumentException(self::ERROR_WORKFLOW_START_DUPLICATION);

[$execution, $handle] = $this->getStarter()->updateWithStart(
$workflowType,
$workflowStub->getOptions() ?? WorkflowOptions::new(),
$update,
$updateArgs,
$startArgs,
);

$workflowStub->setExecution($execution);

return $handle instanceof \Throwable
? throw $handle
: $handle;
}

public function newWorkflowStub(
string $class,
?WorkflowOptions $options = null,
Expand Down
37 changes: 37 additions & 0 deletions src/Client/WorkflowClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@

namespace Temporal\Client;

use JetBrains\PhpStorm\Deprecated;
use Temporal\Api\Enums\V1\HistoryEventFilterType;
use Temporal\Client\Common\ClientContextInterface;
use Temporal\Client\Common\Paginator;
use Temporal\Client\GRPC\ServiceClientInterface;
use Temporal\Client\Update\UpdateHandle;
use Temporal\Client\Update\UpdateOptions;
use Temporal\Client\Workflow\CountWorkflowExecutions;
use Temporal\Client\Workflow\WorkflowExecutionHistory;
use Temporal\Workflow\WorkflowExecution;
Expand All @@ -37,14 +40,48 @@ public function start($workflow, ...$args): WorkflowRunInterface;
* Starts untyped and typed workflow stubs in async mode. Sends signal on start.
*
* @param object|WorkflowStubInterface $workflow
* @param non-empty-string $signal
*
* @since 2.12.0
*/
public function signalWithStart(
$workflow,
string $signal,
array $signalArgs = [],
array $startArgs = [],
): WorkflowRunInterface;

/**
* @deprecated Use {@see self::signalWithStart()} instead.
*/
#[Deprecated(replacement: '%class%->signalWithStart(%parametersList%)')]
public function startWithSignal(
$workflow,
string $signal,
array $signalArgs = [],
array $startArgs = [],
): WorkflowRunInterface;

/**
* Starts untyped and typed workflow stubs in async mode. Sends Update on start.
*
* @param object|WorkflowStubInterface $workflow
* @param non-empty-string|UpdateOptions $update Name of the update handler or update options.
* @param array $updateArgs
* @param array $startArgs
*
* @return UpdateHandle
*
* @note Experimental feature.
* @since 2.12.0
*/
public function updateWithStart(
$workflow,
string|UpdateOptions $update,
array $updateArgs = [],
array $startArgs = [],
): UpdateHandle;

/**
* Creates workflow client stub that can be used to start a single workflow execution.
*
Expand Down
1 change: 0 additions & 1 deletion src/Client/WorkflowOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ public function __construct()
}

/**
*
* @return self return a new {@see self} instance with merged options
*/
public function mergeWith(?MethodRetry $retry = null, ?CronSchedule $cron = null): self
Expand Down
3 changes: 3 additions & 0 deletions src/Client/WorkflowStubInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
*/
interface WorkflowStubInterface extends WorkflowRunInterface
{
/**
* @return non-empty-string|null
*/
public function getWorkflowType(): ?string;

/**
Expand Down
Loading

0 comments on commit 001cfe1

Please sign in to comment.