diff --git a/src/Internal/Workflow/ChildWorkflowStub.php b/src/Internal/Workflow/ChildWorkflowStub.php index 5c5f890e..614c54d1 100644 --- a/src/Internal/Workflow/ChildWorkflowStub.php +++ b/src/Internal/Workflow/ChildWorkflowStub.php @@ -62,6 +62,21 @@ public function getExecution(): PromiseInterface return $this->execution->promise(); } + public function start(... $args): PromiseInterface + { + if ($this->request !== null) { + throw new \LogicException('Child workflow already has been executed'); + } + + $this->request = new ExecuteChildWorkflow( + $this->workflow, + EncodedValues::fromValues($args), + $this->getOptionsArray() + ); + + return $this->request($this->request); + } + /** * {@inheritDoc} */ diff --git a/src/Workflow.php b/src/Workflow.php index de4b8c5b..424d149a 100644 --- a/src/Workflow.php +++ b/src/Workflow.php @@ -25,6 +25,7 @@ use Temporal\Workflow\ChildWorkflowStubInterface; use Temporal\Workflow\ContinueAsNewOptions; use Temporal\Workflow\ExternalWorkflowStubInterface; +use Temporal\Workflow\ParentClosePolicy; use Temporal\Workflow\ScopedContextInterface; use Temporal\Internal\Workflow\WorkflowContext; use Temporal\Workflow\WorkflowExecution; @@ -634,6 +635,7 @@ public static function executeChildWorkflow( * This method is equivalent to {@see Workflow::executeChildWorkflow}, but * it takes the workflow class as the first argument, and the further api * is built on the basis of calls to the methods of the passed workflow. + * For starting abandon child workflow {@see Workflow::newUntypedChildWorkflowStub()}. * * * // Any workflow interface example: @@ -696,6 +698,23 @@ public static function newChildWorkflowStub(string $class, ChildWorkflowOptions * } * * + * To start abandoned child workflow use `yield` and method `start()`: + * + * + * #[WorkflowMethod] + * public function handler() + * { + * // ExampleWorkflow proxy + * $workflow = Workflow::newUntypedChildWorkflowStub( + * 'WorkflowName', + * ChildWorkflowOptions::new()->withParentClosePolicy(ParentClosePolicy::POLICY_ABANDON) + * ); + * + * // Start child workflow + * yield $workflow->start(42); + * } + * + * * @param string $name * @param ChildWorkflowOptions|null $options * @return ChildWorkflowStubInterface diff --git a/src/Workflow/ChildWorkflowStubInterface.php b/src/Workflow/ChildWorkflowStubInterface.php index 0d14a8fb..3ee19820 100644 --- a/src/Workflow/ChildWorkflowStubInterface.php +++ b/src/Workflow/ChildWorkflowStubInterface.php @@ -40,6 +40,12 @@ public function getOptions(): ChildWorkflowOptions; */ public function execute(array $args = [], $returnType = null): PromiseInterface; + /** + * @param array $args + * @return CompletableResultInterface + */ + public function start(... $args): PromiseInterface; + /** * @param string $name * @param array $args diff --git a/tests/Fixtures/src/Workflow/AbandonedChildWithTimerWorkflow.php b/tests/Fixtures/src/Workflow/AbandonedChildWithTimerWorkflow.php index 9339a172..e2251660 100644 --- a/tests/Fixtures/src/Workflow/AbandonedChildWithTimerWorkflow.php +++ b/tests/Fixtures/src/Workflow/AbandonedChildWithTimerWorkflow.php @@ -14,7 +14,7 @@ #[WorkflowInterface] class AbandonedChildWithTimerWorkflow { - #[WorkflowMethod] + #[WorkflowMethod('abandoned_workflow')] public function wait(int $timeoutInSeconds) { Workflow::timer($timeoutInSeconds); diff --git a/tests/Fixtures/src/Workflow/ParentWithAbandonedChildWorkflow.php b/tests/Fixtures/src/Workflow/ParentWithAbandonedChildWorkflow.php index 0a519de5..0f2bb18d 100644 --- a/tests/Fixtures/src/Workflow/ParentWithAbandonedChildWorkflow.php +++ b/tests/Fixtures/src/Workflow/ParentWithAbandonedChildWorkflow.php @@ -16,13 +16,13 @@ class ParentWithAbandonedChildWorkflow #[WorkflowMethod] public function start(int $childTimeoutInSeconds) { - $child = Workflow::newChildWorkflowStub( - AbandonedChildWithTimerWorkflow::class, + $child = Workflow::newUntypedChildWorkflowStub( + 'abandoned_workflow', ChildWorkflowOptions::new() ->withParentClosePolicy(ParentClosePolicy::POLICY_ABANDON) ); - $child->wait($childTimeoutInSeconds); + yield $child->start($childTimeoutInSeconds); return 'Welcome from parent'; } diff --git a/tests/Functional/Client/AwaitTestCase.php b/tests/Functional/Client/AwaitTestCase.php index da120bf4..0b4f1a5a 100644 --- a/tests/Functional/Client/AwaitTestCase.php +++ b/tests/Functional/Client/AwaitTestCase.php @@ -16,6 +16,7 @@ use Temporal\Exception\Failure\ActivityFailure; use Temporal\Exception\Failure\ApplicationFailure; use Temporal\Exception\Failure\CanceledFailure; +use Temporal\Testing\WithoutTimeSkipping; use Temporal\Tests\Workflow\AggregatedWorkflow; use Temporal\Tests\Workflow\LoopWithSignalCoroutinesWorkflow; use Temporal\Tests\Workflow\LoopWorkflow; @@ -28,6 +29,8 @@ */ class AwaitTestCase extends ClientTestCase { + use WithoutTimeSkipping; + public function testSimpleAwait() { $client = $this->createClient(); diff --git a/tests/Functional/Client/ExternalWorkflowTestCase.php b/tests/Functional/Client/ExternalWorkflowTestCase.php index f69f37b7..d6a17250 100644 --- a/tests/Functional/Client/ExternalWorkflowTestCase.php +++ b/tests/Functional/Client/ExternalWorkflowTestCase.php @@ -13,12 +13,15 @@ use Temporal\Exception\Client\WorkflowFailedException; use Temporal\Exception\Failure\CanceledFailure; +use Temporal\Testing\WithoutTimeSkipping; use Temporal\Tests\Workflow\LoopKillerWorkflow; use Temporal\Tests\Workflow\LoopSignallingWorkflow; use Temporal\Tests\Workflow\LoopWorkflow; class ExternalWorkflowTestCase extends ClientTestCase { + use WithoutTimeSkipping; + public function testSignalWorkflowExecution() { $client = $this->createClient();