Skip to content

Commit cd9964b

Browse files
authored
Merge branch 'master' into workflow-id-conflict-policy
2 parents 14796cb + 0179c48 commit cd9964b

File tree

6 files changed

+179
-8
lines changed

6 files changed

+179
-8
lines changed

resources/scripts/generate-client.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@
106106
);
107107
$m->setReturnType('static');
108108
$interface->addMethodFromGenerator($m);
109+
// withAuthKey(string $key): static
110+
$m = new MethodGenerator(
111+
'withAuthKey',
112+
[Generator\ParameterGenerator::fromArray(['type' => '\Stringable|string', 'name' => 'key'])],
113+
MethodGenerator::FLAG_PUBLIC,
114+
);
115+
$m->setReturnType('static');
116+
$interface->addMethodFromGenerator($m);
109117
// public function getConnection(): ConnectionInterface
110118
$m = new MethodGenerator(
111119
'getConnection',

src/Client/GRPC/BaseClient.php

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ abstract class BaseClient implements ServiceClientInterface
4040

4141
private Connection $connection;
4242
private ContextInterface $context;
43+
private \Stringable|string $apiKey = '';
4344

4445
/**
4546
* @param WorkflowServiceClient|Closure(): WorkflowServiceClient $workflowService Service Client or its factory
@@ -74,6 +75,21 @@ public function withContext(ContextInterface $context): static
7475
return $clone;
7576
}
7677

78+
/**
79+
* Set the authentication token for the service client.
80+
*
81+
* This is the equivalent of providing an "Authorization" header with "Bearer " + the given key.
82+
* This will overwrite any "Authorization" header that may be on the context before each request to the
83+
* Temporal service.
84+
* You may pass your own {@see \Stringable} implementation to be able to change the key dynamically.
85+
*/
86+
public function withAuthKey(\Stringable|string $key): static
87+
{
88+
$clone = clone $this;
89+
$clone->apiKey = $key;
90+
return $clone;
91+
}
92+
7793
/**
7894
* Close the communication channel associated with this stub.
7995
*/
@@ -157,8 +173,8 @@ final public function withInterceptorPipeline(?Pipeline $pipeline): static
157173
{
158174
$clone = clone $this;
159175
/** @see GrpcClientInterceptor::interceptCall() */
160-
$callable = $pipeline?->with(Closure::fromCallable([$clone, 'call']), 'interceptCall');
161-
$clone->invokePipeline = $callable === null ? null : Closure::fromCallable($callable);
176+
$callable = $pipeline?->with($clone->call(...), 'interceptCall');
177+
$clone->invokePipeline = $callable === null ? null : $callable(...);
162178
return $clone;
163179
}
164180

@@ -224,10 +240,18 @@ public function getConnection(): ConnectionInterface {
224240
*
225241
* @throw ClientException
226242
*/
227-
protected function invoke(string $method, object $arg, ?ContextInterface $ctx = null)
243+
protected function invoke(string $method, object $arg, ?ContextInterface $ctx = null): mixed
228244
{
229245
$ctx ??= $this->context;
230246

247+
// Add the API key to the context
248+
$key = (string)$this->apiKey;
249+
if ($key !== '') {
250+
$ctx = $ctx->withMetadata([
251+
'Authorization' => ["Bearer $key"],
252+
]);
253+
}
254+
231255
return $this->invokePipeline !== null
232256
? ($this->invokePipeline)($method, $arg, $ctx)
233257
: $this->call($method, $arg, $ctx);

src/Client/GRPC/ServiceClient.php

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,11 @@ public function DescribeWorkflowExecution(V1\DescribeWorkflowExecutionRequest $a
729729
}
730730

731731
/**
732-
* DescribeTaskQueue returns information about the target task queue.
732+
* DescribeTaskQueue returns the following information about the target task queue,
733+
* broken down by Build ID:
734+
* - List of pollers
735+
* - Workflow Reachability status
736+
* - Backlog info for Workflow and/or Activity tasks
733737
*
734738
* @param V1\DescribeTaskQueueRequest $arg
735739
* @param ContextInterface|null $ctx
@@ -873,6 +877,8 @@ public function ListSchedules(V1\ListSchedulesRequest $arg, ContextInterface $ct
873877
}
874878

875879
/**
880+
* Deprecated. Use `UpdateWorkerVersioningRules`.
881+
*
876882
* Allows users to specify sets of worker build id versions on a per task queue
877883
* basis. Versions
878884
* are ordered, and may be either compatible with some extant version, or a new
@@ -906,6 +912,7 @@ public function UpdateWorkerBuildIdCompatibility(V1\UpdateWorkerBuildIdCompatibi
906912
}
907913

908914
/**
915+
* Deprecated. Use `GetWorkerVersioningRules`.
909916
* Fetches the worker build id versioning sets for a task queue.
910917
*
911918
* @param V1\GetWorkerBuildIdCompatibilityRequest $arg
@@ -919,6 +926,41 @@ public function GetWorkerBuildIdCompatibility(V1\GetWorkerBuildIdCompatibilityRe
919926
}
920927

921928
/**
929+
* Allows updating the Build ID assignment and redirect rules for a given Task
930+
* Queue.
931+
* WARNING: Worker Versioning is not yet stable and the API and behavior may change
932+
* incompatibly.
933+
* (-- api-linter: core::0127::http-annotation=disabled
934+
* aip.dev/not-precedent: We do yet expose versioning API to HTTP. --)
935+
*
936+
* @param V1\UpdateWorkerVersioningRulesRequest $arg
937+
* @param ContextInterface|null $ctx
938+
* @return V1\UpdateWorkerVersioningRulesResponse
939+
* @throws ServiceClientException
940+
*/
941+
public function UpdateWorkerVersioningRules(V1\UpdateWorkerVersioningRulesRequest $arg, ContextInterface $ctx = null) : V1\UpdateWorkerVersioningRulesResponse
942+
{
943+
return $this->invoke("UpdateWorkerVersioningRules", $arg, $ctx);
944+
}
945+
946+
/**
947+
* Fetches the Build ID assignment and redirect rules for a Task Queue.
948+
* WARNING: Worker Versioning is not yet stable and the API and behavior may change
949+
* incompatibly.
950+
*
951+
* @param V1\GetWorkerVersioningRulesRequest $arg
952+
* @param ContextInterface|null $ctx
953+
* @return V1\GetWorkerVersioningRulesResponse
954+
* @throws ServiceClientException
955+
*/
956+
public function GetWorkerVersioningRules(V1\GetWorkerVersioningRulesRequest $arg, ContextInterface $ctx = null) : V1\GetWorkerVersioningRulesResponse
957+
{
958+
return $this->invoke("GetWorkerVersioningRules", $arg, $ctx);
959+
}
960+
961+
/**
962+
* Deprecated. Use `DescribeTaskQueue`.
963+
*
922964
* Fetches task reachability to determine whether a worker may be retired.
923965
* The request may specify task queues to query for or let the server fetch all
924966
* task queues mapped to the given

src/Client/GRPC/ServiceClientInterface.php

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface ServiceClientInterface
1616
{
1717
public function getContext() : ContextInterface;
1818
public function withContext(ContextInterface $context) : static;
19+
public function withAuthKey(\Stringable|string $key) : static;
1920
public function getConnection() : \Temporal\Client\GRPC\Connection\ConnectionInterface;
2021
public function getServerCapabilities() : ?\Temporal\Client\Common\ServerCapabilities;
2122
/**
@@ -585,7 +586,11 @@ public function QueryWorkflow(V1\QueryWorkflowRequest $arg, ContextInterface $ct
585586
*/
586587
public function DescribeWorkflowExecution(V1\DescribeWorkflowExecutionRequest $arg, ContextInterface $ctx = null) : V1\DescribeWorkflowExecutionResponse;
587588
/**
588-
* DescribeTaskQueue returns information about the target task queue.
589+
* DescribeTaskQueue returns the following information about the target task queue,
590+
* broken down by Build ID:
591+
* - List of pollers
592+
* - Workflow Reachability status
593+
* - Backlog info for Workflow and/or Activity tasks
589594
*
590595
* @param V1\DescribeTaskQueueRequest $arg
591596
* @param ContextInterface|null $ctx
@@ -685,6 +690,8 @@ public function DeleteSchedule(V1\DeleteScheduleRequest $arg, ContextInterface $
685690
*/
686691
public function ListSchedules(V1\ListSchedulesRequest $arg, ContextInterface $ctx = null) : V1\ListSchedulesResponse;
687692
/**
693+
* Deprecated. Use `UpdateWorkerVersioningRules`.
694+
*
688695
* Allows users to specify sets of worker build id versions on a per task queue
689696
* basis. Versions
690697
* are ordered, and may be either compatible with some extant version, or a new
@@ -714,6 +721,7 @@ public function ListSchedules(V1\ListSchedulesRequest $arg, ContextInterface $ct
714721
*/
715722
public function UpdateWorkerBuildIdCompatibility(V1\UpdateWorkerBuildIdCompatibilityRequest $arg, ContextInterface $ctx = null) : V1\UpdateWorkerBuildIdCompatibilityResponse;
716723
/**
724+
* Deprecated. Use `GetWorkerVersioningRules`.
717725
* Fetches the worker build id versioning sets for a task queue.
718726
*
719727
* @param V1\GetWorkerBuildIdCompatibilityRequest $arg
@@ -723,6 +731,33 @@ public function UpdateWorkerBuildIdCompatibility(V1\UpdateWorkerBuildIdCompatibi
723731
*/
724732
public function GetWorkerBuildIdCompatibility(V1\GetWorkerBuildIdCompatibilityRequest $arg, ContextInterface $ctx = null) : V1\GetWorkerBuildIdCompatibilityResponse;
725733
/**
734+
* Allows updating the Build ID assignment and redirect rules for a given Task
735+
* Queue.
736+
* WARNING: Worker Versioning is not yet stable and the API and behavior may change
737+
* incompatibly.
738+
* (-- api-linter: core::0127::http-annotation=disabled
739+
* aip.dev/not-precedent: We do yet expose versioning API to HTTP. --)
740+
*
741+
* @param V1\UpdateWorkerVersioningRulesRequest $arg
742+
* @param ContextInterface|null $ctx
743+
* @return V1\UpdateWorkerVersioningRulesResponse
744+
* @throws ServiceClientException
745+
*/
746+
public function UpdateWorkerVersioningRules(V1\UpdateWorkerVersioningRulesRequest $arg, ContextInterface $ctx = null) : V1\UpdateWorkerVersioningRulesResponse;
747+
/**
748+
* Fetches the Build ID assignment and redirect rules for a Task Queue.
749+
* WARNING: Worker Versioning is not yet stable and the API and behavior may change
750+
* incompatibly.
751+
*
752+
* @param V1\GetWorkerVersioningRulesRequest $arg
753+
* @param ContextInterface|null $ctx
754+
* @return V1\GetWorkerVersioningRulesResponse
755+
* @throws ServiceClientException
756+
*/
757+
public function GetWorkerVersioningRules(V1\GetWorkerVersioningRulesRequest $arg, ContextInterface $ctx = null) : V1\GetWorkerVersioningRulesResponse;
758+
/**
759+
* Deprecated. Use `DescribeTaskQueue`.
760+
*
726761
* Fetches task reachability to determine whether a worker may be retired.
727762
* The request may specify task queues to query for or let the server fetch all
728763
* task queues mapped to the given

tests/Unit/Client/GRPC/BaseClientTestCase.php

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Temporal\Client\GRPC\Connection\ConnectionState;
1414
use Temporal\Client\GRPC\ContextInterface;
1515
use Temporal\Client\GRPC\ServiceClient;
16+
use Temporal\Internal\Interceptor\Pipeline;
1617

1718
class BaseClientTestCase extends TestCase
1819
{
@@ -80,9 +81,55 @@ public function testWithContext(): void
8081
$this->assertNotSame($client, $client2);
8182
}
8283

84+
public function testWithAuthKey(): void
85+
{
86+
$client = $this->createClientMock();
87+
$context = $client->getContext();
88+
$client2 = $client->withAuthKey('test-key');
89+
90+
// Client immutability
91+
$this->assertNotSame($client, $client2);
92+
// Old context was not modified
93+
$this->assertSame($context, $client->getContext());
94+
// New context is the same as the old one
95+
// because the auth key is added to the context before API method call
96+
$this->assertSame($context, $client2->getContext());
97+
98+
$ctx1 = $client->testCall()->ctx;
99+
self::assertInstanceOf(ContextInterface::class, $ctx1);
100+
$this->assertArrayNotHasKey('Authorization', $ctx1->getMetadata());
101+
102+
$ctx2 = $client2->testCall()->ctx;
103+
self::assertInstanceOf(ContextInterface::class, $ctx2);
104+
$this->assertArrayHasKey('Authorization', $ctx2->getMetadata());
105+
$this->assertSame(['Bearer test-key'], $ctx2->getMetadata()['Authorization']);
106+
}
107+
108+
public function testWithDynamicAuthKey(): void
109+
{
110+
$client = $this->createClientMock()->withAuthKey(new class implements \Stringable {
111+
public function __toString(): string
112+
{
113+
static $counter = 0;
114+
$counter++;
115+
return "test-key-$counter";
116+
}
117+
});
118+
119+
$ctx = $client->testCall()->ctx;
120+
self::assertInstanceOf(ContextInterface::class, $ctx);
121+
$this->assertArrayHasKey('Authorization', $ctx->getMetadata());
122+
$this->assertSame(['Bearer test-key-1'], $ctx->getMetadata()['Authorization']);
123+
124+
$ctx2 = $client->testCall()->ctx;
125+
self::assertInstanceOf(ContextInterface::class, $ctx2);
126+
$this->assertArrayHasKey('Authorization', $ctx2->getMetadata());
127+
$this->assertSame(['Bearer test-key-2'], $ctx2->getMetadata()['Authorization']);
128+
}
129+
83130
private function createClientMock(?callable $serviceClientFactory = null): BaseClient
84131
{
85-
return new class($serviceClientFactory ?? static fn() => new class extends WorkflowServiceClient {
132+
return (new class($serviceClientFactory ?? static fn() => new class extends WorkflowServiceClient {
86133
public function __construct()
87134
{
88135
}
@@ -104,6 +151,22 @@ public function getSystemInfo(
104151
->setCapabilities((new Capabilities)->setSupportsSchedules(true))
105152
->setServerVersion('1.2.3');
106153
}
107-
};
154+
155+
public function testCall(): mixed
156+
{
157+
return $this->invoke("testCall", (object)[], null);
158+
}
159+
})->withInterceptorPipeline(
160+
Pipeline::prepare([new class implements \Temporal\Interceptor\GrpcClientInterceptor {
161+
public function interceptCall(
162+
string $method,
163+
object $arg,
164+
ContextInterface $ctx,
165+
callable $next
166+
): object {
167+
return (object)['method' => $method, 'arg' => $arg, 'ctx' => $ctx, 'next' => $next];
168+
}
169+
}]),
170+
);
108171
}
109172
}

tests/Unit/Client/Mapper/WorkflowExecutionInfoMapperTestCase.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ public function testFromPayload(): void
6464
'state_transition_count' => 1,
6565
'history_size_bytes' => 1,
6666
'most_recent_worker_version_stamp' => (new \Temporal\Api\Common\V1\WorkerVersionStamp())
67-
// ->setBundleId('bundleId')
6867
->setBuildId('buildId')
6968
->setUseVersioning(true),
7069
]),

0 commit comments

Comments
 (0)