Skip to content

Commit cc35329

Browse files
authored
Send ApiKey to RoadRunner with WorkerInfo (#539)
1 parent a775cb1 commit cc35329

File tree

9 files changed

+107
-40
lines changed

9 files changed

+107
-40
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"roadrunner-php/roadrunner-api-dto": "^1.9.0",
3535
"roadrunner-php/version-checker": "^1.0",
3636
"spiral/attributes": "^3.1.6",
37-
"spiral/roadrunner": "^2024.1",
37+
"spiral/roadrunner": "^2024.3",
3838
"spiral/roadrunner-cli": "^2.5",
3939
"spiral/roadrunner-kv": "^4.2",
4040
"spiral/roadrunner-worker": "^3.5",

psalm-baseline.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,7 @@
14771477
<code><![CDATA[new static(
14781478
$converter ?? DataConverter::createDefault(),
14791479
$rpc ?? Goridge::create(),
1480+
$credentials ?? ServiceCredentials::create(),
14801481
)]]></code>
14811482
</UnsafeInstantiation>
14821483
</file>

src/Client/GRPC/BaseClient.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ public function withContext(ContextInterface $context): static
145145
* This will overwrite any "Authorization" header that may be on the context before each request to the
146146
* Temporal service.
147147
* You may pass your own {@see \Stringable} implementation to be able to change the key dynamically.
148+
*
149+
* @link https://docs.temporal.io/cloud/api-keys
148150
*/
149151
public function withAuthKey(\Stringable|string $key): static
150152
{

src/Internal/Transport/Router/GetWorkerInfo.php

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,17 @@
1818
use Temporal\Internal\Declaration\Prototype\WorkflowPrototype;
1919
use Temporal\Internal\Marshaller\MarshallerInterface;
2020
use Temporal\Internal\Repository\RepositoryInterface;
21+
use Temporal\Worker\ServiceCredentials;
2122
use Temporal\Worker\Transport\Command\ServerRequestInterface;
2223
use Temporal\Worker\WorkerInterface;
2324

2425
final class GetWorkerInfo extends Route
2526
{
26-
private RepositoryInterface $queues;
27-
private MarshallerInterface $marshaller;
28-
29-
public function __construct(RepositoryInterface $queues, MarshallerInterface $marshaller)
30-
{
31-
$this->queues = $queues;
32-
$this->marshaller = $marshaller;
33-
}
27+
public function __construct(
28+
private readonly RepositoryInterface $queues,
29+
private readonly MarshallerInterface $marshaller,
30+
private readonly ServiceCredentials $credentials,
31+
) {}
3432

3533
public function handle(ServerRequestInterface $request, array $headers, Deferred $resolver): void
3634
{
@@ -64,7 +62,7 @@ private function workerToArray(WorkerInterface $worker): array
6462
// ActivityInfo[]
6563
'Activities' => $this->map($worker->getActivities(), $activityMap),
6664
'PhpSdkVersion' => SdkVersion::getSdkVersion(),
67-
'Flags' => (object) [],
65+
'Flags' => (object) $this->prepareFlags(),
6866
];
6967
}
7068

@@ -78,4 +76,14 @@ private function map(iterable $items, \Closure $map): array
7876

7977
return $result;
8078
}
79+
80+
/**
81+
* @return array<non-empty-string, mixed>
82+
*/
83+
private function prepareFlags(): array
84+
{
85+
return [
86+
'ApiKey' => $this->credentials->apiKey,
87+
];
88+
}
8189
}

src/Worker/ServiceCredentials.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Temporal\Worker;
6+
7+
use Temporal\Internal\Traits\CloneWith;
8+
9+
/**
10+
* DTO with credential configuration for connecting RoadRunner to the Temporal service.
11+
*/
12+
final class ServiceCredentials
13+
{
14+
use CloneWith;
15+
16+
public readonly string $apiKey;
17+
18+
private function __construct()
19+
{
20+
$this->apiKey = '';
21+
}
22+
23+
public static function create(): self
24+
{
25+
return new self();
26+
}
27+
28+
/**
29+
* Set the authentication token for API calls.
30+
*
31+
* To update the API key in runtime, call the `UpdateAPIKey` RPC method with the new key:
32+
*
33+
* $result = \Temporal\Worker\Transport\Goridge::create()->call(
34+
* 'temporal.UpdateAPIKey',
35+
* $newApiKey,
36+
* );
37+
*
38+
* @link https://docs.temporal.io/cloud/api-keys
39+
* @since SDK 2.12.0
40+
* @since RoadRunner 2024.3.0
41+
*/
42+
public function withApiKey(string $key): static
43+
{
44+
/** @see self::$apiKey */
45+
return $this->with('apiKey', $key);
46+
}
47+
}

src/WorkerFactory.php

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
use Temporal\Worker\Environment\Environment;
4343
use Temporal\Worker\Environment\EnvironmentInterface;
4444
use Temporal\Worker\LoopInterface;
45+
use Temporal\Worker\ServiceCredentials;
4546
use Temporal\Worker\Transport\Codec\CodecInterface;
4647
use Temporal\Worker\Transport\Codec\JsonCodec;
4748
use Temporal\Worker\Transport\Codec\ProtoCodec;
@@ -74,29 +75,10 @@ class WorkerFactory implements WorkerFactoryInterface, LoopInterface
7475
{
7576
use EventEmitterTrait;
7677

77-
/**
78-
* @var string
79-
*/
8078
private const ERROR_MESSAGE_TYPE = 'Received message type must be a string, but %s given';
81-
82-
/**
83-
* @var string
84-
*/
8579
private const ERROR_HEADERS_TYPE = 'Received headers type must be a string, but %s given';
86-
87-
/**
88-
* @var string
89-
*/
9080
private const ERROR_HEADER_NOT_STRING_TYPE = 'Header "%s" argument type must be a string, but %s given';
91-
92-
/**
93-
* @var string
94-
*/
9581
private const ERROR_QUEUE_NOT_FOUND = 'Cannot find a worker for task queue "%s"';
96-
97-
/**
98-
* @var string
99-
*/
10082
private const HEADER_TASK_QUEUE = 'taskQueue';
10183

10284
protected DataConverterInterface $converter;
@@ -112,7 +94,6 @@ class WorkerFactory implements WorkerFactoryInterface, LoopInterface
11294
protected ClientInterface $client;
11395
protected ServerInterface $server;
11496
protected QueueInterface $responses;
115-
protected RPCConnectionInterface $rpc;
11697

11798
/**
11899
* @var MarshallerInterface<array>
@@ -123,21 +104,22 @@ class WorkerFactory implements WorkerFactoryInterface, LoopInterface
123104

124105
public function __construct(
125106
DataConverterInterface $dataConverter,
126-
RPCConnectionInterface $rpc,
107+
protected RPCConnectionInterface $rpc,
108+
ServiceCredentials $credentials,
127109
) {
128110
$this->converter = $dataConverter;
129-
$this->rpc = $rpc;
130-
131-
$this->boot();
111+
$this->boot($credentials);
132112
}
133113

134114
public static function create(
135115
?DataConverterInterface $converter = null,
136116
?RPCConnectionInterface $rpc = null,
117+
?ServiceCredentials $credentials = null,
137118
): WorkerFactoryInterface {
138119
return new static(
139120
$converter ?? DataConverter::createDefault(),
140121
$rpc ?? Goridge::create(),
122+
$credentials ?? ServiceCredentials::create(),
141123
);
142124
}
143125

@@ -237,10 +219,10 @@ protected function createTaskQueue(): RepositoryInterface
237219
return new ArrayRepository();
238220
}
239221

240-
protected function createRouter(): RouterInterface
222+
protected function createRouter(ServiceCredentials $credentials): RouterInterface
241223
{
242224
$router = new Router();
243-
$router->add(new Router\GetWorkerInfo($this->queues, $this->marshaller));
225+
$router->add(new Router\GetWorkerInfo($this->queues, $this->marshaller, $credentials));
244226

245227
return $router;
246228
}
@@ -269,12 +251,12 @@ protected function createMarshaller(ReaderInterface $reader): MarshallerInterfac
269251
return new Marshaller(new AttributeMapperFactory($reader));
270252
}
271253

272-
private function boot(): void
254+
private function boot(ServiceCredentials $credentials): void
273255
{
274256
$this->reader = $this->createReader();
275257
$this->marshaller = $this->createMarshaller($this->reader);
276258
$this->queues = $this->createTaskQueue();
277-
$this->router = $this->createRouter();
259+
$this->router = $this->createRouter($credentials);
278260
$this->responses = $this->createQueue();
279261
$this->client = $this->createClient();
280262
$this->server = $this->createServer();

testing/src/WorkerFactory.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Temporal\Internal\ServiceContainer;
1414
use Temporal\Worker\ActivityInvocationCache\ActivityInvocationCacheInterface;
1515
use Temporal\Worker\ActivityInvocationCache\RoadRunnerActivityInvocationCache;
16+
use Temporal\Worker\ServiceCredentials;
1617
use Temporal\Worker\Transport\Goridge;
1718
use Temporal\Worker\Transport\RPCConnectionInterface;
1819
use Temporal\Worker\Worker;
@@ -27,21 +28,24 @@ public function __construct(
2728
DataConverterInterface $dataConverter,
2829
RPCConnectionInterface $rpc,
2930
ActivityInvocationCacheInterface $activityCache,
31+
ServiceCredentials $credentials,
3032
) {
3133
$this->activityCache = $activityCache;
3234

33-
parent::__construct($dataConverter, $rpc);
35+
parent::__construct($dataConverter, $rpc, $credentials);
3436
}
3537

3638
public static function create(
3739
?DataConverterInterface $converter = null,
3840
?RPCConnectionInterface $rpc = null,
41+
?ServiceCredentials $credentials = null,
3942
?ActivityInvocationCacheInterface $activityCache = null,
4043
): static {
4144
return new static(
4245
$converter ?? DataConverter::createDefault(),
4346
$rpc ?? Goridge::create(),
4447
$activityCache ?? RoadRunnerActivityInvocationCache::create($converter),
48+
$credentials ?? ServiceCredentials::create(),
4549
);
4650
}
4751

tests/Unit/Framework/WorkerFactoryMock.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use Temporal\Worker\Environment\Environment;
3434
use Temporal\Worker\Environment\EnvironmentInterface;
3535
use Temporal\Worker\LoopInterface;
36+
use Temporal\Worker\ServiceCredentials;
3637
use Temporal\Worker\Transport\Codec\CodecInterface;
3738
use Temporal\Worker\Transport\Command\ServerRequestInterface;
3839
use Temporal\Worker\Transport\Command\ServerResponseInterface;
@@ -183,7 +184,7 @@ private function createReader(): ReaderInterface
183184
private function createRouter(): RouterInterface
184185
{
185186
$router = new Router();
186-
$router->add(new Router\GetWorkerInfo($this->queues, $this->marshaller));
187+
$router->add(new Router\GetWorkerInfo($this->queues, $this->marshaller, ServiceCredentials::create()));
187188

188189
return $router;
189190
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Temporal\Tests\Unit\Worker;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Temporal\Worker\ServiceCredentials;
9+
10+
class ServiceCredentialsTestCase extends TestCase
11+
{
12+
public function testWithApiKeyImmutability()
13+
{
14+
$dto = ServiceCredentials::create();
15+
16+
$new = $dto->withApiKey('test');
17+
18+
$this->assertNotSame($dto, $new);
19+
$this->assertSame('test', $new->apiKey);
20+
$this->assertSame('', $dto->apiKey);
21+
}
22+
}

0 commit comments

Comments
 (0)