Skip to content

Commit

Permalink
Merge pull request #83: multiple Temporal Client configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
roxblnfk authored Aug 30, 2024
2 parents 6251b2e + 22401af commit ffa7f4d
Show file tree
Hide file tree
Showing 15 changed files with 713 additions and 285 deletions.
3 changes: 3 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# These are supported funding model platforms

github: spiral
22 changes: 11 additions & 11 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@
"chat": "https://discord.gg/V6EK4he"
},
"license": "MIT",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/spiral"
}
],
"authors": [
{
"name": "Anton Titov (wolfy-j)",
"email": "[email protected]"
},
{
"name": "Pavel Butchnev (butschster)",
"name": "Pavel Buchnev (butschster)",
"email": "[email protected]"
},
{
Expand All @@ -38,15 +44,15 @@
"require": {
"php": "^8.1",
"spiral/boot": "^3.13",
"spiral/attributes": "^2.8 || ^3.0",
"spiral/attributes": "^2.8 || ^3.1.5",
"spiral/tokenizer": "^3.13",
"spiral/scaffolder": "^3.13",
"spiral/roadrunner-bridge": "^2.0 || ^3.5",
"temporal/sdk": "^2.7"
"spiral/roadrunner-bridge": "^2.0 || ^3.6",
"temporal/sdk": "^2.10"
},
"require-dev": {
"spiral/framework": "^3.13",
"spiral/testing": "^2.7",
"spiral/testing": "^2.8",
"vimeo/psalm": "^5.23"
},
"autoload": {
Expand All @@ -60,12 +66,6 @@
"Spiral\\TemporalBridge\\Tests\\": "tests/src"
}
},
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/roadrunner-server"
}
],
"scripts": {
"test": "vendor/bin/phpunit",
"psalm": "vendor/bin/psalm --no-cache --config=psalm.xml ./src"
Expand Down
1 change: 1 addition & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
</projectFiles>
<issueHandlers>
<MissingClassConstType errorLevel="suppress" />
<DeprecatedMethod errorLevel="suppress" />
<DeprecatedInterface>
<errorLevel type="suppress">
<file name="src/Commands/InfoCommand.php"/>
Expand Down
35 changes: 29 additions & 6 deletions src/Bootloader/TemporalBridgeBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
use Spiral\Core\FactoryInterface;
use Spiral\RoadRunnerBridge\Bootloader\RoadRunnerBootloader;
use Spiral\TemporalBridge\Commands;
use Spiral\TemporalBridge\Config\ClientConfig;
use Spiral\TemporalBridge\Config\ConnectionConfig;
use Spiral\TemporalBridge\Config\TemporalConfig;
use Spiral\TemporalBridge\DeclarationLocator;
use Spiral\TemporalBridge\DeclarationLocatorInterface;
Expand Down Expand Up @@ -95,9 +97,7 @@ public function defineSingletons(): array

DataConverterInterface::class => static fn() => DataConverter::createDefault(),
PipelineProvider::class => [self::class, 'initPipelineProvider'],
ServiceClientInterface::class => static fn(
TemporalConfig $config,
): ServiceClientInterface => ServiceClient::create($config->getAddress()),
ServiceClientInterface::class => [self::class, 'initServiceClient'],
];
}

Expand Down Expand Up @@ -156,18 +156,41 @@ protected function initConfig(EnvironmentInterface $env): void
$this->config->setDefaults(
TemporalConfig::CONFIG,
[
'address' => $env->get('TEMPORAL_ADDRESS', '127.0.0.1:7233'),
'namespace' => 'App\\Endpoint\\Temporal\\Workflow',
'client' => $env->get('TEMPORAL_CONNECTION', 'default'),
'clients' => [
'default' => ClientConfig::new(
ConnectionConfig::new(
address: $env->get('TEMPORAL_ADDRESS', '127.0.0.1:7233'),
),
),
],
'defaultWorker' => (string)$env->get(
'TEMPORAL_TASK_QUEUE',
TemporalWorkerFactoryInterface::DEFAULT_TASK_QUEUE,
),
'workers' => [],
'clientOptions' => null,
],
);
}

protected function initServiceClient(TemporalConfig $config): ServiceClientInterface
{
$client = $config->getClientConfig($config->getDefaultClient());
$connection = $client->connection;

$result = $connection->isSecure()
? ServiceClient::createSSL(
address: $connection->address,
crt: $connection->tlsConfig->rootCerts,
clientKey: $connection->tlsConfig->privateKey,
clientPem: $connection->tlsConfig->certChain,
overrideServerName: $connection->tlsConfig->serverName,
)
: ServiceClient::create(address: $connection->address);

return $result->withContext($client->context);
}

protected function initPipelineProvider(TemporalConfig $config, FactoryInterface $factory): PipelineProvider
{
/** @var Interceptor[] $interceptors */
Expand Down
60 changes: 60 additions & 0 deletions src/Config/ClientConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace Spiral\TemporalBridge\Config;

use Temporal\Client\ClientOptions;
use Temporal\Client\GRPC\Context;
use Temporal\Client\GRPC\ContextInterface;

/**
* Temporal Client configuration.
*
* ClientConfig::new(
* ConnectionConfig::new('localhost:7233')
* ->withTls(
* privateKey: '/my-project.key',
* certChain: '/my-project.pem',
* ),
* (new ClientOptions())
* ->withNamespace('default'),
* Context::default()
* ->withTimeout(4.5)
* ->withRetryOptions(
* RpcRetryOptions::new()
* ->withMaximumAttempts(5)
* ->withInitialInterval(3)
* ->withMaximumInterval(10)
* ->withBackoffCoefficient(1.6)
* ),
* ),
* ),
*/
final class ClientConfig
{
private function __construct(
public readonly ConnectionConfig $connection,
public readonly ClientOptions $options,
public readonly ContextInterface $context,
) {}

/**
* Create a new client configuration.
*
* @param ConnectionConfig $connection
* @param ClientOptions|null $options
* @param ContextInterface|null $context Default Service Client context.
*/
public static function new(
ConnectionConfig $connection,
?ClientOptions $options = null,
?ContextInterface $context = null,
): self {
return new self(
$connection,
$options ?? new ClientOptions(),
$context ?? Context::default(),
);
}
}
93 changes: 93 additions & 0 deletions src/Config/ConnectionConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

declare(strict_types=1);

namespace Spiral\TemporalBridge\Config;

/**
* Temporal connection and credentials configuration.
*
* How to connect to local Temporal server:
*
* ConnectionConfig::new('localhost:7233'),
*
* How to connect to Temporal Cloud:
*
* ConnectionConfig::new('foo-bar-default.baz.tmprl.cloud:7233')
* ->withTls(
* privateKey: '/my-project.key',
* certChain: '/my-project.pem',
* ),
*/
final class ConnectionConfig
{
/**
* @param non-empty-string $address
* @param non-empty-string|\Stringable|null $authToken
*/
private function __construct(
public readonly string $address,
public readonly ?TlsConfig $tlsConfig = null,
public readonly string|\Stringable|null $authToken = null,
) {}

/**
* Check if the connection is secure.
*
* @psalm-assert-if-true TlsConfig $this->tlsConfig
* @psalm-assert-if-false null $this->tlsConfig
*/
public function isSecure(): bool
{
return $this->tlsConfig !== null;
}

/**
* @param non-empty-string $address
*/
public static function new(
string $address,
): self {
return new self($address);
}

/**
* Set the TLS configuration for the connection.
*
* @param non-empty-string|null $rootCerts Root certificates string or file in PEM format.
* If null provided, default gRPC root certificates are used.
* @param non-empty-string|null $privateKey Client private key string or file in PEM format.
* @param non-empty-string|null $certChain Client certificate chain string or file in PEM format.
* @param non-empty-string|null $serverName Server name override for TLS verification.
*/
public function withTls(
?string $rootCerts = null,
?string $privateKey = null,
?string $certChain = null,
?string $serverName = null,
): self {
return new self(
$this->address,
new TlsConfig($rootCerts, $privateKey, $certChain, $serverName),
);
}

/**
* Set the authentication token for the service client.
*
* This is the equivalent of providing an "Authorization" header with "Bearer " + the given key.
* This will overwrite any "Authorization" header that may be on the context before each request to the
* Temporal service.
* You may pass your own {@see \Stringable} implementation to be able to change the key dynamically.
*
* @param non-empty-string|\Stringable|null $authToken
*/
public function withAuthKey(string|\Stringable|null $authToken): self
{
return new self(
$this->address,
$this->tlsConfig,
$authToken,
);
}
}
Loading

0 comments on commit ffa7f4d

Please sign in to comment.