Skip to content

Commit

Permalink
Merge pull request #414: Expose API to describe Workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
roxblnfk authored Apr 9, 2024
2 parents c13912c + fe2e151 commit 0ae7ac6
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 1 deletion.
22 changes: 22 additions & 0 deletions src/Client/Workflow/WorkflowExecutionDescription.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Temporal\Client\Workflow;

use Temporal\Workflow\WorkflowExecutionInfo;

/**
* DTO that contains detailed information about Workflow Execution.
*
* @see \Temporal\Api\Workflowservice\V1\DescribeWorkflowExecutionResponse
*
* @internal
*/
final class WorkflowExecutionDescription
{
public function __construct(
public readonly WorkflowExecutionInfo $info,
) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Temporal\Client;
namespace Temporal\Client\Workflow;

use Generator;
use IteratorAggregate;
Expand Down
1 change: 1 addition & 0 deletions src/Client/WorkflowClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Temporal\Client\Common\Paginator;
use Temporal\Client\GRPC\ServiceClientInterface;
use Temporal\Client\Workflow\CountWorkflowExecutions;
use Temporal\Client\Workflow\WorkflowExecutionHistory;
use Temporal\DataConverter\DataConverter;
use Temporal\DataConverter\DataConverterInterface;
use Temporal\DataConverter\Type;
Expand Down
1 change: 1 addition & 0 deletions src/Client/WorkflowClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Temporal\Client\Common\Paginator;
use Temporal\Client\GRPC\ServiceClientInterface;
use Temporal\Client\Workflow\CountWorkflowExecutions;
use Temporal\Client\Workflow\WorkflowExecutionHistory;
use Temporal\Workflow\WorkflowExecution;
use Temporal\Workflow\WorkflowExecutionInfo as WorkflowExecutionInfoDto;
use Temporal\Workflow\WorkflowRunInterface;
Expand Down
12 changes: 12 additions & 0 deletions src/Interceptor/Trait/WorkflowClientCallsInterceptorTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@

namespace Temporal\Interceptor\Trait;

use Temporal\Client\Workflow\WorkflowExecutionDescription;
use Temporal\DataConverter\EncodedValues;
use Temporal\Interceptor\WorkflowClient\CancelInput;
use Temporal\Interceptor\WorkflowClient\DescribeInput;
use Temporal\Interceptor\WorkflowClient\GetResultInput;
use Temporal\Interceptor\WorkflowClient\QueryInput;
use Temporal\Interceptor\WorkflowClient\SignalInput;
Expand Down Expand Up @@ -110,4 +112,14 @@ public function terminate(TerminateInput $input, callable $next): void
{
$next($input);
}

/**
* Default implementation of the `describe` method.
*
* @see WorkflowClientCallsInterceptor::describe()
*/
public function describe(DescribeInput $input, callable $next): WorkflowExecutionDescription
{
return $next($input);
}
}
38 changes: 38 additions & 0 deletions src/Interceptor/WorkflowClient/DescribeInput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

/**
* This file is part of Temporal package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Temporal\Interceptor\WorkflowClient;

use Temporal\Workflow\WorkflowExecution;

/**
* @psalm-immutable
*/
class DescribeInput
{
/**
* @no-named-arguments
* @internal Don't use the constructor. Use {@see self::with()} instead.
*/
public function __construct(
public readonly WorkflowExecution $workflowExecution,
public readonly string $namespace,
) {
}

public function with(
WorkflowExecution $workflowExecution = null,
string $namespace = null,
): self {
return new self(
$workflowExecution ?? $this->workflowExecution,
$namespace ?? $this->namespace,
);
}
}
10 changes: 10 additions & 0 deletions src/Interceptor/WorkflowClientCallsInterceptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@

namespace Temporal\Interceptor;

use Temporal\Client\Workflow\WorkflowExecutionDescription;
use Temporal\DataConverter\ValuesInterface;
use Temporal\Interceptor\Trait\WorkflowClientCallsInterceptorTrait;
use Temporal\Interceptor\WorkflowClient\CancelInput;
use Temporal\Interceptor\WorkflowClient\DescribeInput;
use Temporal\Interceptor\WorkflowClient\GetResultInput;
use Temporal\Interceptor\WorkflowClient\QueryInput;
use Temporal\Interceptor\WorkflowClient\SignalInput;
Expand Down Expand Up @@ -110,4 +112,12 @@ public function cancel(CancelInput $input, callable $next): void;
* @return void
*/
public function terminate(TerminateInput $input, callable $next): void;

/**
* @param DescribeInput $input
* @param callable(DescribeInput): void $next
*
* @return WorkflowExecutionDescription
*/
public function describe(DescribeInput $input, callable $next): WorkflowExecutionDescription;
}
6 changes: 6 additions & 0 deletions src/Internal/Client/WorkflowRun.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Temporal\Internal\Client;

use Temporal\Client\Workflow\WorkflowExecutionDescription;
use Temporal\Client\WorkflowStubInterface;
use Temporal\DataConverter\Type;
use Temporal\Workflow\WorkflowExecution;
Expand Down Expand Up @@ -43,4 +44,9 @@ public function getResult($type = null, int $timeout = null): mixed
{
return $this->stub->getResult($type ?? $this->returnType, $timeout);
}

public function describe(): WorkflowExecutionDescription
{
return $this->stub->describe();
}
}
30 changes: 30 additions & 0 deletions src/Internal/Client/WorkflowStub.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Temporal\Api\History\V1\HistoryEvent;
use Temporal\Api\Query\V1\WorkflowQuery;
use Temporal\Api\Update\V1\Request as UpdateRequestMessage;
use Temporal\Api\Workflowservice\V1\DescribeWorkflowExecutionRequest;
use Temporal\Api\Workflowservice\V1\GetWorkflowExecutionHistoryRequest;
use Temporal\Api\Workflowservice\V1\QueryWorkflowRequest;
use Temporal\Api\Workflowservice\V1\RequestCancelWorkflowExecutionRequest;
Expand All @@ -34,6 +35,7 @@
use Temporal\Client\Update\UpdateHandle;
use Temporal\Client\Update\UpdateOptions;
use Temporal\Client\Update\WaitPolicy;
use Temporal\Client\Workflow\WorkflowExecutionDescription;
use Temporal\Client\WorkflowOptions;
use Temporal\Client\WorkflowStubInterface;
use Temporal\Common\Uuid;
Expand All @@ -58,6 +60,7 @@
use Temporal\Interceptor\Header;
use Temporal\Interceptor\HeaderInterface;
use Temporal\Interceptor\WorkflowClient\CancelInput;
use Temporal\Interceptor\WorkflowClient\DescribeInput;
use Temporal\Interceptor\WorkflowClient\GetResultInput;
use Temporal\Interceptor\WorkflowClient\QueryInput;
use Temporal\Interceptor\WorkflowClient\SignalInput;
Expand All @@ -68,6 +71,7 @@
use Temporal\Interceptor\WorkflowClientCallsInterceptor;
use Temporal\Internal\Interceptor\HeaderCarrier;
use Temporal\Internal\Interceptor\Pipeline;
use Temporal\Internal\Mapper\WorkflowExecutionInfoMapper;
use Temporal\Workflow\WorkflowExecution;

final class WorkflowStub implements WorkflowStubInterface, HeaderCarrier
Expand Down Expand Up @@ -496,6 +500,32 @@ function (GetResultInput $input): ?EncodedValues {
return $result->getValue(0, $type);
}

public function describe(): WorkflowExecutionDescription
{
$this->assertStarted(__FUNCTION__);

return $this->interceptors->with(
function (DescribeInput $input): WorkflowExecutionDescription {
$request = new DescribeWorkflowExecutionRequest();
$request->setNamespace($input->namespace);
$request->setExecution($input->workflowExecution->toProtoWorkflowExecution());

$response = $this->serviceClient->DescribeWorkflowExecution($request);
$mapper = new WorkflowExecutionInfoMapper($this->converter);

/** @psalm-suppress PossiblyNullArgument */
return new WorkflowExecutionDescription(
info: $mapper->fromMessage($response->getWorkflowExecutionInfo()),
);
},
/** @see WorkflowClientCallsInterceptor::describe() */
'describe',
)(new DescribeInput(
$this->execution,
$this->clientOptions->namespace,
));
}

/**
* @param string $method
* @psalm-assert !null $this->execution
Expand Down
3 changes: 3 additions & 0 deletions src/Workflow/WorkflowRunInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Temporal\Workflow;

use Temporal\Client\Workflow\WorkflowExecutionDescription;
use Temporal\DataConverter\Type;
use Temporal\Exception\Client\WorkflowFailedException;

Expand Down Expand Up @@ -47,4 +48,6 @@ public function getExecution(): WorkflowExecution;
* @see DateInterval
*/
public function getResult($type = null, int $timeout = null): mixed;

public function describe(): WorkflowExecutionDescription;
}
40 changes: 40 additions & 0 deletions tests/Functional/Client/UntypedWorkflowStubTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Temporal\Exception\IllegalStateException;
use Temporal\Exception\InvalidArgumentException;
use Temporal\Tests\Unit\Declaration\Fixture\WorkflowWithoutHandler;
use Temporal\Workflow\WorkflowExecutionStatus;

/**
* @group client
Expand Down Expand Up @@ -212,6 +213,45 @@ public function testTerminated()
}
}

public function testDescribe(): void
{
$client = $this->createClient();
$simple = $client->newUntypedWorkflowStub('SimpleSignalledWorkflowWithSleep');

$run = $client->start($simple, -1);
$startAt = \microtime(true);

do {
$stubDescription = $simple->describe();
// 5 seconds limit
if (\microtime(true) - $startAt > 5) {
throw new InvalidArgumentException('Workflow execution not started');
}
// wait for workflow was started on a worker
} while ($stubDescription->info->historyLength < 5);

$runDescription = $run->describe();

self::assertEquals($stubDescription, $runDescription);
self::assertSame(WorkflowExecutionStatus::Running, $runDescription->info->status);

$simple->terminate('user triggered');
try {
// Wait for termination
$simple->getResult();
} catch (WorkflowFailedException $e) {
$this->assertInstanceOf(TerminatedFailure::class, $e->getPrevious());
}

$stubDescription = $simple->describe();
$runDescription = $run->describe();

// After termination
self::assertEquals($stubDescription, $runDescription);
self::assertSame(WorkflowExecutionStatus::Terminated, $runDescription->info->status);
self::assertSame(WorkflowExecutionStatus::Terminated, $stubDescription->info->status);
}

public function testSignalRunningWorkflowWithInheritedSignal()
{
$client = $this->createClient();
Expand Down

0 comments on commit 0ae7ac6

Please sign in to comment.