From aad7a9bdf53749d3886cc6dbba6db28c9093671a Mon Sep 17 00:00:00 2001 From: tuutti Date: Tue, 3 Sep 2024 09:07:46 +0300 Subject: [PATCH 1/5] UHF-10559: Add support for secondary key authentication --- drush.services.yml | 6 --- helfi_api_base.services.yml | 56 ++++---------------- src/Azure/PubSub/AccessTokenType.php | 13 +++++ src/Azure/PubSub/PubSubClientFactory.php | 33 +++++++++--- src/Azure/PubSub/PubSubManager.php | 67 ++++++++++++++++-------- src/Azure/PubSub/Settings.php | 5 +- src/Azure/PubSub/SettingsFactory.php | 4 +- src/Commands/PubSubCommands.php | 3 ++ 8 files changed, 101 insertions(+), 86 deletions(-) create mode 100644 src/Azure/PubSub/AccessTokenType.php diff --git a/drush.services.yml b/drush.services.yml index 61735ee1..25017c35 100644 --- a/drush.services.yml +++ b/drush.services.yml @@ -7,12 +7,6 @@ services: - '@datetime.time' tags: - { name: drush.command } - helfi_api_base.pubsub_commands: - class: \Drupal\helfi_api_base\Commands\PubSubCommands - arguments: - - '@helfi_api_base.pubsub_manager' - tags: - - { name: drush.command } helfi_api_base.deploy_commands: class: \Drupal\helfi_api_base\Commands\DeployCommands arguments: ['@event_dispatcher'] diff --git a/helfi_api_base.services.yml b/helfi_api_base.services.yml index 1c4e2ffa..86b93760 100644 --- a/helfi_api_base.services.yml +++ b/helfi_api_base.services.yml @@ -108,53 +108,15 @@ services: arguments: - '@config.factory' - Drupal\helfi_api_base\Azure\PubSub\SettingsFactory: '@helfi_api_base.pubsub_settings_factory' - helfi_api_base.pubsub_settings_factory: - class: Drupal\helfi_api_base\Azure\PubSub\SettingsFactory - arguments: - - '@helfi_api_base.vault_manager' - - Drupal\helfi_api_base\Azure\PubSub\PubSubClientFactory: '@helfi_api_base.pubsub_client_factory' - helfi_api_base.pubsub_client_factory: - class: Drupal\helfi_api_base\Azure\PubSub\PubSubClientFactory - - helfi_api_base.pubsub_client: - public: false - class: \WebSocket\Client - factory: ['@helfi_api_base.pubsub_client_factory', 'create'] - arguments: - - '@helfi_api_base.pubsub_settings' - - '@datetime.time' - - Drupal\helfi_api_base\Azure\PubSub\Settings: '@helfi_api_base.pubsub_settings' - helfi_api_base.pubsub_settings: - class: Drupal\helfi_api_base\Azure\PubSub\Settings - factory: ['@helfi_api_base.pubsub_settings_factory', 'create'] - - Drupal\helfi_api_base\Azure\PubSub\PubSubManager: '@helfi_api_base.pubsub_manager' - helfi_api_base.pubsub_manager: - class: Drupal\helfi_api_base\Azure\PubSub\PubSubManager - arguments: - - '@helfi_api_base.pubsub_client' - - '@event_dispatcher' - - '@datetime.time' - - '@helfi_api_base.pubsub_settings' - - Drupal\helfi_api_base\Cache\CacheTagInvalidatorInterface: '@helfi_api_base.cache_tag_invalidator' - Drupal\helfi_api_base\Cache\CacheTagInvalidator: '@helfi_api_base.cache_tag_invalidator' - helfi_api_base.cache_tag_invalidator: - class: Drupal\helfi_api_base\Cache\CacheTagInvalidator - arguments: - - '@helfi_api_base.pubsub_manager' - - Drupal\helfi_api_base\EventSubscriber\CacheTagInvalidatorSubscriber: '@helfi_api_base.cache_tag_invalidator_subscriber' - helfi_api_base.cache_tag_invalidator_subscriber: - class: Drupal\helfi_api_base\EventSubscriber\CacheTagInvalidatorSubscriber - arguments: - - '@cache_tags.invalidator' - - '@helfi_api_base.environment_resolver' - tags: - - { name: event_subscriber } + Drupal\helfi_api_base\Azure\PubSub\PubSubClientFactory: ~ + Drupal\helfi_api_base\Azure\PubSub\Settings: + factory: ['Drupal\helfi_api_base\Azure\PubSub\SettingsFactory', 'create'] + Drupal\helfi_api_base\Azure\PubSub\PubSubManager: ~ + Drupal\helfi_api_base\Azure\PubSub\PubSubManagerInterface: '@Drupal\helfi_api_base\Azure\PubSub\PubSubManager' + Drupal\helfi_api_base\Cache\CacheTagInvalidatorInterface: '@Drupal\helfi_api_base\Cache\CacheTagInvalidator' + Drupal\helfi_api_base\Cache\CacheTagInvalidator: ~ + + Drupal\helfi_api_base\EventSubscriber\CacheTagInvalidatorSubscriber: ~ Drupal\helfi_api_base\Entity\Revision\RevisionManager: '@helfi_api_base.revision_manager' helfi_api_base.revision_manager: diff --git a/src/Azure/PubSub/AccessTokenType.php b/src/Azure/PubSub/AccessTokenType.php new file mode 100644 index 00000000..dced4b5f --- /dev/null +++ b/src/Azure/PubSub/AccessTokenType.php @@ -0,0 +1,13 @@ +endpoint, '/'), $settings->hub); + public function create(AccessTokenType $type) : Client { + $url = sprintf('wss://%s/client/hubs/%s', rtrim($this->settings->endpoint, '/'), $this->settings->hub); + + $accessKey = $this->settings->accessKey; + if ($type === AccessTokenType::Secondary) { + $accessKey = $this->settings->secondaryAccessKey; + } $authorizationToken = JWT::encode([ 'aud' => $url, - 'iat' => $time->getCurrentTime(), - 'exp' => $time->getCurrentTime() + 3600, + 'iat' => $this->time->getCurrentTime(), + 'exp' => $this->time->getCurrentTime() + 3600, 'role' => [ 'webpubsub.sendToGroup', 'webpubsub.joinLeaveGroup', ], - ], $settings->accessKey, 'HS256'); + ], $accessKey, 'HS256'); return new Client($url, [ 'headers' => [ diff --git a/src/Azure/PubSub/PubSubManager.php b/src/Azure/PubSub/PubSubManager.php index 0658782b..b7f09d03 100644 --- a/src/Azure/PubSub/PubSubManager.php +++ b/src/Azure/PubSub/PubSubManager.php @@ -6,7 +6,6 @@ use Drupal\Component\Datetime\TimeInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; -use WebSocket\Client; use WebSocket\ConnectionException; /** @@ -24,8 +23,6 @@ final class PubSubManager implements PubSubManagerInterface { /** * Constructs a new instance. * - * @param \WebSocket\Client $client - * The websocket client. * @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $eventDispatcher * The event dispatcher service. * @param \Drupal\Component\Datetime\TimeInterface $time @@ -34,13 +31,41 @@ final class PubSubManager implements PubSubManagerInterface { * The PubSub settings. */ public function __construct( - private readonly Client $client, + private readonly PubSubClientFactory $clientFactory, private readonly EventDispatcherInterface $eventDispatcher, private readonly TimeInterface $time, private readonly Settings $settings, ) { } + private function clientReceive() : string { + try { + return (string) $this->clientFactory + ->create(AccessTokenType::Primary) + ->receive(); + } + catch (ConnectionException) { + } + return (string) $this->clientFactory + ->create(AccessTokenType::Secondary) + ->receive(); + } + + private function clientText(array $message) : void { + $message = $this->encodeMessage($message); + + try { + $this->clientFactory + ->create(AccessTokenType::Primary) + ->text($message); + } + catch (ConnectionException) { + } + $this->clientFactory + ->create(AccessTokenType::Secondary) + ->text($message); + } + /** * Joins a group. * @@ -52,16 +77,14 @@ private function joinGroup() : void { if ($this->joinedGroup) { return; } - $this->client->text( - $this->encodeMessage([ - 'type' => 'joinGroup', - 'group' => $this->settings->group, - ]) - ); + $this->clientText([ + 'type' => 'joinGroup', + 'group' => $this->settings->group, + ]); try { // Wait until we've actually joined the group. - $message = $this->decodeMessage((string) $this->client->receive()); + $message = $this->decodeMessage($this->clientReceive()); if (isset($message['event']) && $message['event'] === 'connected') { $this->joinedGroup = TRUE; @@ -135,17 +158,15 @@ public function sendMessage(array $message) : self { $this->assertSettings(); $this->joinGroup(); - $this->client - ->text( - $this->encodeMessage([ - 'type' => 'sendToGroup', - 'group' => $this->settings->group, - 'dataType' => 'json', - 'data' => $message + [ - 'timestamp' => $this->time->getCurrentTime(), - ], - ]) - ); + $this + ->clientText([ + 'type' => 'sendToGroup', + 'group' => $this->settings->group, + 'dataType' => 'json', + 'data' => $message + [ + 'timestamp' => $this->time->getCurrentTime(), + ], + ]); return $this; } @@ -157,7 +178,7 @@ public function receive() : string { $this->assertSettings(); $this->joinGroup(); - $message = (string) $this->client->receive(); + $message = $this->clientReceive(); $json = $this->decodeMessage($message); $this->eventDispatcher diff --git a/src/Azure/PubSub/Settings.php b/src/Azure/PubSub/Settings.php index 166e844b..fcd0d6aa 100644 --- a/src/Azure/PubSub/Settings.php +++ b/src/Azure/PubSub/Settings.php @@ -19,13 +19,16 @@ final class Settings { * @param string $endpoint * The API endpoint. * @param string $accessKey - * The API access token. + * The API access key. + * @param string $secondaryAccessKey + * The secondary API access key. */ public function __construct( public readonly string $hub, public readonly string $group, public readonly string $endpoint, public readonly string $accessKey, + public readonly string $secondaryAccessKey, ) { } diff --git a/src/Azure/PubSub/SettingsFactory.php b/src/Azure/PubSub/SettingsFactory.php index f7ef26e9..715f5769 100644 --- a/src/Azure/PubSub/SettingsFactory.php +++ b/src/Azure/PubSub/SettingsFactory.php @@ -34,6 +34,7 @@ public function create() : Settings { 'group' => '', 'endpoint' => '', 'access_key' => '', + 'secondary_access_key' => '', ]; if ($settings = $this->vaultManager->get('pubsub')) { @@ -50,7 +51,8 @@ public function create() : Settings { $data->hub ?: '', $data->group ?: '', $data->endpoint ?: '', - $data->access_key ?: '' + $data->access_key ?: '', + $data->secondary_access_key ?: '', ); } diff --git a/src/Commands/PubSubCommands.php b/src/Commands/PubSubCommands.php index 7fd0619e..d0f9a94b 100644 --- a/src/Commands/PubSubCommands.php +++ b/src/Commands/PubSubCommands.php @@ -4,6 +4,7 @@ namespace Drupal\helfi_api_base\Commands; +use Drupal\Core\DependencyInjection\AutowireTrait; use Drupal\helfi_api_base\Azure\PubSub\PubSubManagerInterface; use Drush\Attributes\Command; use Drush\Commands\DrushCommands; @@ -20,6 +21,8 @@ */ final class PubSubCommands extends DrushCommands { + use AutowireTrait; + public const MAX_MESSAGES = 100; public const CLIENT_TIMEOUT = 120; From a840c58e14ce877e51faa8cc0c35d2f877f3bc61 Mon Sep 17 00:00:00 2001 From: tuutti Date: Tue, 3 Sep 2024 11:22:36 +0300 Subject: [PATCH 2/5] UHF-10559: Refactored PubSub to work with access key rotation --- helfi_api_base.services.yml | 4 +- src/Azure/PubSub/AccessTokenType.php | 13 -- src/Azure/PubSub/PubSubClientFactory.php | 13 +- .../PubSub/PubSubClientFactoryInterface.php | 25 ++++ src/Azure/PubSub/PubSubManager.php | 114 ++++++++++------- src/Azure/PubSub/PubSubManagerInterface.php | 11 -- src/Azure/PubSub/Settings.php | 9 +- src/Azure/PubSub/SettingsFactory.php | 30 ++--- src/{ => Drush}/Commands/PubSubCommands.php | 14 +- .../Kernel/Cache/CacheTagInvalidatorTest.php | 2 + .../Azure/PubSub/PubSubClientFactoryTest.php | 6 +- .../Unit/Azure/PubSub/PubSubManagerTest.php | 121 ++++-------------- tests/src/Unit/Azure/PubSub/SettingsTest.php | 26 ++-- .../src/Unit/Commands/PubSubCommandsTest.php | 6 +- 14 files changed, 168 insertions(+), 226 deletions(-) delete mode 100644 src/Azure/PubSub/AccessTokenType.php create mode 100644 src/Azure/PubSub/PubSubClientFactoryInterface.php rename src/{ => Drush}/Commands/PubSubCommands.php (81%) diff --git a/helfi_api_base.services.yml b/helfi_api_base.services.yml index 86b93760..ad4d726c 100644 --- a/helfi_api_base.services.yml +++ b/helfi_api_base.services.yml @@ -109,8 +109,10 @@ services: - '@config.factory' Drupal\helfi_api_base\Azure\PubSub\PubSubClientFactory: ~ + Drupal\helfi_api_base\Azure\PubSub\PubSubClientFactoryInterface: '@Drupal\helfi_api_base\Azure\PubSub\PubSubClientFactory' + Drupal\helfi_api_base\Azure\PubSub\SettingsFactory: ~ Drupal\helfi_api_base\Azure\PubSub\Settings: - factory: ['Drupal\helfi_api_base\Azure\PubSub\SettingsFactory', 'create'] + factory: ['@Drupal\helfi_api_base\Azure\PubSub\SettingsFactory', 'create'] Drupal\helfi_api_base\Azure\PubSub\PubSubManager: ~ Drupal\helfi_api_base\Azure\PubSub\PubSubManagerInterface: '@Drupal\helfi_api_base\Azure\PubSub\PubSubManager' Drupal\helfi_api_base\Cache\CacheTagInvalidatorInterface: '@Drupal\helfi_api_base\Cache\CacheTagInvalidator' diff --git a/src/Azure/PubSub/AccessTokenType.php b/src/Azure/PubSub/AccessTokenType.php deleted file mode 100644 index dced4b5f..00000000 --- a/src/Azure/PubSub/AccessTokenType.php +++ /dev/null @@ -1,13 +0,0 @@ -settings->endpoint, '/'), $this->settings->hub); - $accessKey = $this->settings->accessKey; - - if ($type === AccessTokenType::Secondary) { - $accessKey = $this->settings->secondaryAccessKey; - } $authorizationToken = JWT::encode([ 'aud' => $url, 'iat' => $this->time->getCurrentTime(), diff --git a/src/Azure/PubSub/PubSubClientFactoryInterface.php b/src/Azure/PubSub/PubSubClientFactoryInterface.php new file mode 100644 index 00000000..7e6efeba --- /dev/null +++ b/src/Azure/PubSub/PubSubClientFactoryInterface.php @@ -0,0 +1,25 @@ +clientFactory - ->create(AccessTokenType::Primary) - ->receive(); + if ($this->client) { + return (string) $this->client->receive(); } - catch (ConnectionException) { + $exception = new ConnectionException('Failed to receive message.'); + + // Initialize client with primary key, fallback to secondary key. + foreach ($this->settings->accessKeys as $key) { + try { + $client = $this->clientFactory->create($key); + $message = (string) $client->receive(); + + $this->client = $client; + + return $message; + } + catch (ConnectionException $exception) { + Error::logException($this->logger, $exception); + } } - return (string) $this->clientFactory - ->create(AccessTokenType::Secondary) - ->receive(); + throw $exception; } + /** + * Sends a text message to PubSub service. + * + * @param array $message + * The message to send. + * + * @throws \JsonException + * @throws \WebSocket\ConnectionException + */ private function clientText(array $message) : void { $message = $this->encodeMessage($message); - try { - $this->clientFactory - ->create(AccessTokenType::Primary) - ->text($message); + if ($this->client) { + $this->client->text($message); + + return; } - catch (ConnectionException) { + $exception = new ConnectionException('Failed to send text.'); + + // Initialize client with primary key, fallback to secondary key. + foreach ($this->settings->accessKeys as $key) { + try { + $client = $this->clientFactory->create($key); + $client->text($message); + $this->client = $client; + return; + } + catch (ConnectionException $exception) { + Error::logException($this->logger, $exception); + } } - $this->clientFactory - ->create(AccessTokenType::Secondary) - ->text($message); + throw $exception; } /** @@ -128,34 +181,10 @@ private function decodeMessage(string $message) : array { return json_decode($message, TRUE, flags: JSON_THROW_ON_ERROR); } - /** - * {@inheritdoc} - */ - public function setTimeout(int $timeout) : self { - $this->client->setTimeout($timeout); - return $this; - } - - /** - * Asserts the settings. - * - * This is used to exit early if required settings are not populated. - */ - private function assertSettings() : void { - $vars = get_object_vars($this->settings); - - foreach ($vars as $key => $value) { - if (empty($this->settings->{$key})) { - throw new ConnectionException("Azure PubSub '$key' is not configured."); - } - } - } - /** * {@inheritdoc} */ public function sendMessage(array $message) : self { - $this->assertSettings(); $this->joinGroup(); $this @@ -175,7 +204,6 @@ public function sendMessage(array $message) : self { * {@inheritdoc} */ public function receive() : string { - $this->assertSettings(); $this->joinGroup(); $message = $this->clientReceive(); diff --git a/src/Azure/PubSub/PubSubManagerInterface.php b/src/Azure/PubSub/PubSubManagerInterface.php index a6085ad0..a0e094fb 100644 --- a/src/Azure/PubSub/PubSubManagerInterface.php +++ b/src/Azure/PubSub/PubSubManagerInterface.php @@ -36,15 +36,4 @@ public function sendMessage(array $message): self; */ public function receive(): string; - /** - * Sets the client timeout. - * - * @param int $timeout - * The timeout in seconds. - * - * @return self - * The self. - */ - public function setTimeout(int $timeout): self; - } diff --git a/src/Azure/PubSub/Settings.php b/src/Azure/PubSub/Settings.php index fcd0d6aa..20c6872b 100644 --- a/src/Azure/PubSub/Settings.php +++ b/src/Azure/PubSub/Settings.php @@ -18,17 +18,14 @@ final class Settings { * The group. * @param string $endpoint * The API endpoint. - * @param string $accessKey - * The API access key. - * @param string $secondaryAccessKey - * The secondary API access key. + * @param array $accessKeys + * The API access keys. */ public function __construct( public readonly string $hub, public readonly string $group, public readonly string $endpoint, - public readonly string $accessKey, - public readonly string $secondaryAccessKey, + public readonly array $accessKeys, ) { } diff --git a/src/Azure/PubSub/SettingsFactory.php b/src/Azure/PubSub/SettingsFactory.php index 715f5769..6855a28d 100644 --- a/src/Azure/PubSub/SettingsFactory.php +++ b/src/Azure/PubSub/SettingsFactory.php @@ -29,30 +29,26 @@ public function __construct( * The PubSub settings object. */ public function create() : Settings { - $data = [ - 'hub' => '', - 'group' => '', - 'endpoint' => '', - 'access_key' => '', - 'secondary_access_key' => '', - ]; - - if ($settings = $this->vaultManager->get('pubsub')) { - foreach ($data as $key => $value) { - if (!isset($settings->data()->{$key})) { - continue; - } - $data[$key] = $settings->data()->{$key}; + if (!$settings = $this->vaultManager->get('pubsub')) { + // Return an empty settings object in case PubSub is not + // configured. + return new Settings('', '', '', []); + } + $data = $settings->data(); + + $accessKeys = []; + foreach (['access_key', 'access_key_secondary'] as $key) { + if (empty($data->{$key})) { + continue; } + $accessKeys[] = $data->{$key}; } - $data = (object) $data; return new Settings( $data->hub ?: '', $data->group ?: '', $data->endpoint ?: '', - $data->access_key ?: '', - $data->secondary_access_key ?: '', + $accessKeys, ); } diff --git a/src/Commands/PubSubCommands.php b/src/Drush/Commands/PubSubCommands.php similarity index 81% rename from src/Commands/PubSubCommands.php rename to src/Drush/Commands/PubSubCommands.php index d0f9a94b..8d71ccb7 100644 --- a/src/Commands/PubSubCommands.php +++ b/src/Drush/Commands/PubSubCommands.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Drupal\helfi_api_base\Commands; +namespace Drupal\helfi_api_base\Drush\Commands; -use Drupal\Core\DependencyInjection\AutowireTrait; use Drupal\helfi_api_base\Azure\PubSub\PubSubManagerInterface; use Drush\Attributes\Command; +use Drush\Commands\AutowireTrait; use Drush\Commands\DrushCommands; use WebSocket\TimeoutException; @@ -24,17 +24,17 @@ final class PubSubCommands extends DrushCommands { use AutowireTrait; public const MAX_MESSAGES = 100; - public const CLIENT_TIMEOUT = 120; /** * Constructs a new instance. * - * @param \Drupal\helfi_api_base\Azure\PubSub\PubSubManagerInterface $pubSubClient + * @param \Drupal\helfi_api_base\Azure\PubSub\PubSubManagerInterface $clientManager * The PubSub client. */ public function __construct( - private readonly PubSubManagerInterface $pubSubClient, + private readonly PubSubManagerInterface $clientManager, ) { + parent::__construct(); } /** @@ -45,11 +45,9 @@ public function __construct( */ #[Command(name: 'helfi:azure:pubsub-listen')] public function listen() : int { - $this->pubSubClient->setTimeout(self::CLIENT_TIMEOUT); - for ($received = 0; $received < self::MAX_MESSAGES; $received++) { try { - $message = $this->pubSubClient->receive(); + $message = $this->clientManager->receive(); $this->io() ->writeln(sprintf('Received message [#%d]: %s', $received, $message)); } diff --git a/tests/src/Kernel/Cache/CacheTagInvalidatorTest.php b/tests/src/Kernel/Cache/CacheTagInvalidatorTest.php index 22420dac..d80c5a29 100644 --- a/tests/src/Kernel/Cache/CacheTagInvalidatorTest.php +++ b/tests/src/Kernel/Cache/CacheTagInvalidatorTest.php @@ -9,6 +9,7 @@ use Drupal\Tests\helfi_api_base\Traits\CacheTagInvalidator; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; +use Psr\Log\LoggerInterface; use WebSocket\Client; /** @@ -75,6 +76,7 @@ public function testInvalidateTags() : void { $this->container->get('event_dispatcher'), $this->container->get('datetime.time'), $this->container->get('helfi_api_base.pubsub_settings'), + $this->prophesize(LoggerInterface::class)->reveal(), ); $this->container->set('helfi_api_base.pubsub_manager', $pubSubManager); $pubSubManager->receive(); diff --git a/tests/src/Unit/Azure/PubSub/PubSubClientFactoryTest.php b/tests/src/Unit/Azure/PubSub/PubSubClientFactoryTest.php index 8b43c2f9..fde80c5a 100644 --- a/tests/src/Unit/Azure/PubSub/PubSubClientFactoryTest.php +++ b/tests/src/Unit/Azure/PubSub/PubSubClientFactoryTest.php @@ -28,10 +28,10 @@ public function testConstruct() : void { 'hub', 'group', 'endpoint', - 'accessToken', + ['accessToken', 'secondaryAccessToken'], ); - $sut = new PubSubClientFactory(); - $client = $sut->create($settings, $this->prophesize(TimeInterface::class)->reveal()); + $sut = new PubSubClientFactory($this->prophesize(TimeInterface::class)->reveal(), $settings); + $client = $sut->create($settings->accessKeys[0]); $this->assertInstanceOf(Client::class, $client); } diff --git a/tests/src/Unit/Azure/PubSub/PubSubManagerTest.php b/tests/src/Unit/Azure/PubSub/PubSubManagerTest.php index e98aa8b7..6f97d77f 100644 --- a/tests/src/Unit/Azure/PubSub/PubSubManagerTest.php +++ b/tests/src/Unit/Azure/PubSub/PubSubManagerTest.php @@ -5,17 +5,20 @@ namespace Drupal\Tests\helfi_api_base\Unit\Azure\PubSub; use Drupal\Component\Datetime\TimeInterface; +use Drupal\helfi_api_base\Azure\PubSub\PubSubClientFactoryInterface; use Drupal\helfi_api_base\Azure\PubSub\PubSubManager; use Drupal\helfi_api_base\Azure\PubSub\Settings; use Drupal\Tests\UnitTestCase; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; +use Psr\Log\LoggerInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use WebSocket\Client; use WebSocket\ConnectionException; /** - * @coversDefaultClass \Drupal\helfi_api_base\Azure\PubSub\PubSubManager + * Tests PubSub manager service. + * * @group helfi_api_base */ class PubSubManagerTest extends UnitTestCase { @@ -23,74 +26,7 @@ class PubSubManagerTest extends UnitTestCase { use ProphecyTrait; /** - * @covers ::__construct - * @covers ::assertSettings - * @covers ::receive - * @covers ::sendMessage - * @covers \Drupal\helfi_api_base\Azure\PubSub\Settings::__construct - * @dataProvider assertSettingsExceptionData - */ - public function testAssertSettingsException(string $method, array $args) : void { - $this->expectException(ConnectionException::class); - $this->expectExceptionMessage("Azure PubSub 'hub' is not configured"); - $sut = new PubSubManager( - $this->prophesize(Client::class)->reveal(), - $this->prophesize(EventDispatcherInterface::class)->reveal(), - $this->prophesize(TimeInterface::class)->reveal(), - new Settings( - '', - 'local', - 'localhost', - 'token', - ) - ); - call_user_func_array([$sut, $method], $args); - } - - /** - * Data provider for testAssertSettingsException. - * - * @return array[] - * The data. - */ - public function assertSettingsExceptionData() : array { - return [ - ['receive', []], - ['sendMessage', [['message' => 'message']]], - ]; - } - - /** - * @covers ::setTimeout - * @covers ::__construct - * @covers ::assertSettings - * @covers \Drupal\helfi_api_base\Azure\PubSub\Settings::__construct - */ - public function testSetTimeout() : void { - $client = $this->prophesize(Client::class); - $client->setTimeout(5)->shouldBeCalled(); - $sut = new PubSubManager( - $client->reveal(), - $this->prophesize(EventDispatcherInterface::class)->reveal(), - $this->prophesize(TimeInterface::class)->reveal(), - new Settings( - 'hub', - 'local', - 'localhost', - 'token', - ) - ); - $sut->setTimeout(5); - } - - /** - * @covers ::sendMessage - * @covers ::joinGroup - * @covers ::encodeMessage - * @covers ::decodeMessage - * @covers ::__construct - * @covers ::assertSettings - * @covers \Drupal\helfi_api_base\Azure\PubSub\Settings::__construct + * Tests joinGroup exceptions. */ public function testJoinGroupException() : void { $time = $this->prophesize(TimeInterface::class); @@ -100,17 +36,21 @@ public function testJoinGroupException() : void { $client->text('{"type":"joinGroup","group":"local"}')->shouldBeCalledTimes(1); $client->send(Argument::any())->shouldNotBeCalled(); $client->receive()->willReturn(''); + $clientFactory = $this->prophesize(PubSubClientFactoryInterface::class); + $clientFactory->create('token') + ->willReturn($client->reveal()); $sut = new PubSubManager( - $client->reveal(), + $clientFactory->reveal(), $this->prophesize(EventDispatcherInterface::class)->reveal(), $time->reveal(), new Settings( 'hub', 'local', 'localhost', - 'token', - ) + ['token'], + ), + $this->prophesize(LoggerInterface::class)->reveal(), ); $this->expectException(ConnectionException::class); $this->expectExceptionMessage('Failed to join a group.'); @@ -118,13 +58,7 @@ public function testJoinGroupException() : void { } /** - * @covers ::sendMessage - * @covers ::joinGroup - * @covers ::encodeMessage - * @covers ::decodeMessage - * @covers ::__construct - * @covers ::assertSettings - * @covers \Drupal\helfi_api_base\Azure\PubSub\Settings::__construct + * Tests sendMessage() and clientText() methods. */ public function testSendMessage() : void { $time = $this->prophesize(TimeInterface::class); @@ -134,17 +68,21 @@ public function testSendMessage() : void { $client->receive()->willReturn('{"type":"event","event":"connected"}'); $client->text('{"type":"joinGroup","group":"local"}')->shouldBeCalledTimes(1); $client->text('{"type":"sendToGroup","group":"local","dataType":"json","data":{"test":"something","timestamp":1234}}')->shouldBeCalledTimes(2); + $clientFactory = $this->prophesize(PubSubClientFactoryInterface::class); + $clientFactory->create('token') + ->willReturn($client->reveal()); $sut = new PubSubManager( - $client->reveal(), + $clientFactory->reveal(), $this->prophesize(EventDispatcherInterface::class)->reveal(), $time->reveal(), new Settings( 'hub', 'local', 'localhost', - 'token', - ) + ['token'], + ), + $this->prophesize(LoggerInterface::class)->reveal(), ); // Send two messages to test that we call ::joinGroup() once. $sut->sendMessage(['test' => 'something']); @@ -152,14 +90,7 @@ public function testSendMessage() : void { } /** - * @covers ::joinGroup - * @covers ::receive - * @covers ::encodeMessage - * @covers ::decodeMessage - * @covers ::__construct - * @covers ::assertSettings - * @covers \Drupal\helfi_api_base\Azure\PubSub\Settings::__construct - * @covers \Drupal\helfi_api_base\Azure\PubSub\PubSubMessage::__construct + * Tests receive() and clientReceive() methods. */ public function testReceive() : void { $expectedMessage = '{"message":"test"}'; @@ -175,17 +106,21 @@ public function testReceive() : void { ); // This called once by ::joinGroup and twice by ::receive(). $client->receive()->shouldBeCalledTimes(3); + $clientFactory = $this->prophesize(PubSubClientFactoryInterface::class); + $clientFactory->create('token') + ->willReturn($client->reveal()); $sut = new PubSubManager( - $client->reveal(), + $clientFactory->reveal(), $dispatcher->reveal(), $this->prophesize(TimeInterface::class)->reveal(), new Settings( 'hub', 'local', 'localhost', - 'token', - ) + ['token'], + ), + $this->prophesize(LoggerInterface::class)->reveal(), ); // Call twice to make sure we only join group once. $this->assertEquals($expectedMessage, $sut->receive()); diff --git a/tests/src/Unit/Azure/PubSub/SettingsTest.php b/tests/src/Unit/Azure/PubSub/SettingsTest.php index 5571f326..a2eff9d2 100644 --- a/tests/src/Unit/Azure/PubSub/SettingsTest.php +++ b/tests/src/Unit/Azure/PubSub/SettingsTest.php @@ -11,19 +11,15 @@ use Drupal\Tests\UnitTestCase; /** - * @coversDefaultClass \Drupal\helfi_api_base\Azure\PubSub\SettingsFactory + * Tests pubsub settings. + * * @group helfi_api_base */ class SettingsTest extends UnitTestCase { /** - * @covers \Drupal\helfi_api_base\Azure\PubSub\Settings::__construct - * @covers ::create - * @covers ::__construct - * @covers \Drupal\helfi_api_base\Vault\VaultManager::__construct - * @covers \Drupal\helfi_api_base\Vault\VaultManager::get - * @covers \Drupal\helfi_api_base\Vault\Json::__construct - * @covers \Drupal\helfi_api_base\Vault\Json::data + * Tests settings. + * * @dataProvider settingsData */ public function testSettings(array $values, array $expectedValues) : void { @@ -36,15 +32,11 @@ public function testSettings(array $values, array $expectedValues) : void { $this->assertSame($expectedValues['hub'], $settings->hub); $this->assertSame($expectedValues['group'], $settings->group); $this->assertSame($expectedValues['endpoint'], $settings->endpoint); - $this->assertSame($expectedValues['access_key'], $settings->accessKey); + $this->assertSame($expectedValues['access_key'], $settings->accessKeys); } /** - * @covers \Drupal\helfi_api_base\Azure\PubSub\Settings::__construct - * @covers ::create - * @covers ::__construct - * @covers \Drupal\helfi_api_base\Vault\VaultManager::__construct - * @covers \Drupal\helfi_api_base\Vault\VaultManager::get + * Tests empty settings. */ public function testEmptySettings() : void { $vaultManager = new VaultManager([]); @@ -54,7 +46,7 @@ public function testEmptySettings() : void { $this->assertSame('', $settings->hub); $this->assertSame('', $settings->group); $this->assertSame('', $settings->endpoint); - $this->assertSame('', $settings->accessKey); + $this->assertSame([], $settings->accessKeys); } /** @@ -77,7 +69,7 @@ public function settingsData() : array { 'hub' => 'hub', 'group' => 'group', 'endpoint' => 'endpoint', - 'access_key' => '123', + 'access_key' => ['123'], ], ], ]; @@ -94,7 +86,7 @@ public function settingsData() : array { 'hub' => '', 'group' => '', 'endpoint' => '', - 'access_key' => '', + 'access_key' => [], ], ]; } diff --git a/tests/src/Unit/Commands/PubSubCommandsTest.php b/tests/src/Unit/Commands/PubSubCommandsTest.php index b69b6eb9..d26e8675 100644 --- a/tests/src/Unit/Commands/PubSubCommandsTest.php +++ b/tests/src/Unit/Commands/PubSubCommandsTest.php @@ -5,7 +5,7 @@ namespace Drupal\Tests\helfi_api_base\Unit\Commands; use Drupal\helfi_api_base\Azure\PubSub\PubSubManagerInterface; -use Drupal\helfi_api_base\Commands\PubSubCommands; +use Drupal\helfi_api_base\Drush\Commands\PubSubCommands; use Drupal\Tests\UnitTestCase; use Drush\Commands\DrushCommands; use Prophecy\Argument; @@ -39,7 +39,6 @@ public function testListen() : void { ->shouldBeCalledTimes(1); $manager = $this->prophesize(PubSubManagerInterface::class); - $manager->setTimeout(PubSubCommands::CLIENT_TIMEOUT)->shouldBeCalled(); $manager->receive()->willReturn($expectedMessage); $sut = new PubSubCommands($manager->reveal()); @@ -60,7 +59,6 @@ public function testExceptionOutput() : void { ->shouldBeCalledTimes(1); $manager = $this->prophesize(PubSubManagerInterface::class); - $manager->setTimeout(PubSubCommands::CLIENT_TIMEOUT)->shouldBeCalled(); $manager->receive()->willThrow(new \JsonException('Syntax error')); $sut = new PubSubCommands($manager->reveal()); @@ -80,7 +78,6 @@ public function testTimeoutException() : void { ->shouldBeCalledTimes(1); $manager = $this->prophesize(PubSubManagerInterface::class); - $manager->setTimeout(PubSubCommands::CLIENT_TIMEOUT)->shouldBeCalled(); $manager->receive()->willThrow(TimeoutException::class); $sut = new PubSubCommands($manager->reveal()); @@ -95,7 +92,6 @@ public function testTimeoutException() : void { public function testConnectionException() : void { $this->expectException(ConnectionException::class); $manager = $this->prophesize(PubSubManagerInterface::class); - $manager->setTimeout(PubSubCommands::CLIENT_TIMEOUT)->shouldBeCalled(); $manager->receive()->willThrow(ConnectionException::class); $sut = new PubSubCommands($manager->reveal()); From d95e599665daa8052059aba84fdf18aeded40be1 Mon Sep 17 00:00:00 2001 From: tuutti Date: Tue, 3 Sep 2024 11:50:15 +0300 Subject: [PATCH 3/5] UHF-10559: Test fixes --- tests/src/Kernel/Cache/CacheTagInvalidatorTest.php | 14 ++++++++++---- tests/src/Unit/Commands/PubSubCommandsTest.php | 12 ++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/src/Kernel/Cache/CacheTagInvalidatorTest.php b/tests/src/Kernel/Cache/CacheTagInvalidatorTest.php index d80c5a29..ed2c2a71 100644 --- a/tests/src/Kernel/Cache/CacheTagInvalidatorTest.php +++ b/tests/src/Kernel/Cache/CacheTagInvalidatorTest.php @@ -4,7 +4,10 @@ namespace Drupal\Tests\helfi_api_base\Kernel\Cache; +use Drupal\helfi_api_base\Azure\PubSub\PubSubClientFactoryInterface; use Drupal\helfi_api_base\Azure\PubSub\PubSubManager; +use Drupal\helfi_api_base\Azure\PubSub\Settings; +use Drupal\helfi_api_base\Cache\CacheTagInvalidator as CacheTagInvalidatorService; use Drupal\KernelTests\KernelTestBase; use Drupal\Tests\helfi_api_base\Traits\CacheTagInvalidator; use Prophecy\Argument; @@ -71,18 +74,21 @@ public function testInvalidateTags() : void { '{"type":"event","event":"connected"}', '{"data": {"tags":["node:123"]}}' ); + $clientFactory = $this->prophesize(PubSubClientFactoryInterface::class); + $clientFactory->create('123')->willReturn($client->reveal()); + $pubSubManager = new PubSubManager( - $client->reveal(), + $clientFactory->reveal(), $this->container->get('event_dispatcher'), $this->container->get('datetime.time'), - $this->container->get('helfi_api_base.pubsub_settings'), + $this->container->get(Settings::class), $this->prophesize(LoggerInterface::class)->reveal(), ); - $this->container->set('helfi_api_base.pubsub_manager', $pubSubManager); + $this->container->set(PubSubManager::class, $pubSubManager); $pubSubManager->receive(); /** @var \Drupal\helfi_api_base\Cache\CacheTagInvalidator $sut */ - $sut = $this->container->get('helfi_api_base.cache_tag_invalidator'); + $sut = $this->container->get(CacheTagInvalidatorService::class); $sut->invalidateTags(['node:123']); $this->assertArrayHasKey('node:123', $cacheTagInvalidator->tags); } diff --git a/tests/src/Unit/Commands/PubSubCommandsTest.php b/tests/src/Unit/Commands/PubSubCommandsTest.php index d26e8675..06547e87 100644 --- a/tests/src/Unit/Commands/PubSubCommandsTest.php +++ b/tests/src/Unit/Commands/PubSubCommandsTest.php @@ -25,8 +25,7 @@ class PubSubCommandsTest extends UnitTestCase { use ProphecyTrait; /** - * @covers ::__construct - * @covers ::listen + * Tests listen. */ public function testListen() : void { $expectedMessage = '{"message":"test"}'; @@ -47,8 +46,7 @@ public function testListen() : void { } /** - * @covers ::listen - * @covers ::__construct + * Tests exception output. */ public function testExceptionOutput() : void { $output = $this->prophesize(OutputInterface::class); @@ -67,8 +65,7 @@ public function testExceptionOutput() : void { } /** - * @covers ::listen - * @covers ::__construct + * Tests timeout exception. */ public function testTimeoutException() : void { $output = $this->prophesize(OutputInterface::class); @@ -86,8 +83,7 @@ public function testTimeoutException() : void { } /** - * @covers ::listen - * @covers ::__construct + * Tests connection exception. */ public function testConnectionException() : void { $this->expectException(ConnectionException::class); From 1ffd02764fc7e59b497c090b39af8e8cb4d75960 Mon Sep 17 00:00:00 2001 From: tuutti Date: Tue, 3 Sep 2024 13:05:51 +0300 Subject: [PATCH 4/5] UHF-10559: Simplified client initialization logic --- src/Azure/PubSub/PubSubManager.php | 110 +++++------------- src/Azure/PubSub/SettingsFactory.php | 2 +- .../Azure/PubSub/PubSubClientFactoryTest.php | 3 +- .../Unit/Azure/PubSub/PubSubManagerTest.php | 39 ++++++- 4 files changed, 63 insertions(+), 91 deletions(-) diff --git a/src/Azure/PubSub/PubSubManager.php b/src/Azure/PubSub/PubSubManager.php index 500766ca..5642081e 100644 --- a/src/Azure/PubSub/PubSubManager.php +++ b/src/Azure/PubSub/PubSubManager.php @@ -24,13 +24,6 @@ final class PubSubManager implements PubSubManagerInterface { */ private ?Client $client = NULL; - /** - * A flag indicating whether we've joined the group. - * - * @var bool - */ - protected bool $joinedGroup = FALSE; - /** * Constructs a new instance. * @@ -55,100 +48,51 @@ public function __construct( } /** - * Receives a message from PubSub service. - * - * @return string - * The received message. - * - * @throws \WebSocket\ConnectionException - */ - private function clientReceive() : string { - if ($this->client) { - return (string) $this->client->receive(); - } - $exception = new ConnectionException('Failed to receive message.'); - - // Initialize client with primary key, fallback to secondary key. - foreach ($this->settings->accessKeys as $key) { - try { - $client = $this->clientFactory->create($key); - $message = (string) $client->receive(); - - $this->client = $client; - - return $message; - } - catch (ConnectionException $exception) { - Error::logException($this->logger, $exception); - } - } - throw $exception; - } - - /** - * Sends a text message to PubSub service. - * - * @param array $message - * The message to send. + * Joins a group. * * @throws \JsonException * @throws \WebSocket\ConnectionException + * @throws \WebSocket\TimeoutException */ - private function clientText(array $message) : void { - $message = $this->encodeMessage($message); - + private function initializeClient() : void { if ($this->client) { - $this->client->text($message); - return; } - $exception = new ConnectionException('Failed to send text.'); + $client = $exception = NULL; // Initialize client with primary key, fallback to secondary key. foreach ($this->settings->accessKeys as $key) { + $exception = NULL; + try { $client = $this->clientFactory->create($key); - $client->text($message); - $this->client = $client; - return; + $client->text($this->encodeMessage([ + 'type' => 'joinGroup', + 'group' => $this->settings->group, + ])); } catch (ConnectionException $exception) { Error::logException($this->logger, $exception); } } - throw $exception; - } - /** - * Joins a group. - * - * @throws \JsonException - * @throws \WebSocket\ConnectionException - * @throws \WebSocket\TimeoutException - */ - private function joinGroup() : void { - if ($this->joinedGroup) { - return; + if ($exception instanceof ConnectionException) { + throw $exception; } - $this->clientText([ - 'type' => 'joinGroup', - 'group' => $this->settings->group, - ]); try { // Wait until we've actually joined the group. - $message = $this->decodeMessage($this->clientReceive()); + $message = $this->decodeMessage((string) $client->receive()); if (isset($message['event']) && $message['event'] === 'connected') { - $this->joinedGroup = TRUE; + $this->client = $client; return; } } catch (\JsonException) { } - - throw new ConnectionException('Failed to join a group.'); + throw new ConnectionException('Failed to initialize the client.'); } /** @@ -185,18 +129,16 @@ private function decodeMessage(string $message) : array { * {@inheritdoc} */ public function sendMessage(array $message) : self { - $this->joinGroup(); - - $this - ->clientText([ - 'type' => 'sendToGroup', - 'group' => $this->settings->group, - 'dataType' => 'json', - 'data' => $message + [ - 'timestamp' => $this->time->getCurrentTime(), - ], - ]); + $this->initializeClient(); + $this->client->text($this->encodeMessage([ + 'type' => 'sendToGroup', + 'group' => $this->settings->group, + 'dataType' => 'json', + 'data' => $message + [ + 'timestamp' => $this->time->getCurrentTime(), + ], + ])); return $this; } @@ -204,9 +146,9 @@ public function sendMessage(array $message) : self { * {@inheritdoc} */ public function receive() : string { - $this->joinGroup(); + $this->initializeClient(); - $message = $this->clientReceive(); + $message = (string) $this->client->receive(); $json = $this->decodeMessage($message); $this->eventDispatcher diff --git a/src/Azure/PubSub/SettingsFactory.php b/src/Azure/PubSub/SettingsFactory.php index 6855a28d..cf2cc72a 100644 --- a/src/Azure/PubSub/SettingsFactory.php +++ b/src/Azure/PubSub/SettingsFactory.php @@ -37,7 +37,7 @@ public function create() : Settings { $data = $settings->data(); $accessKeys = []; - foreach (['access_key', 'access_key_secondary'] as $key) { + foreach (['access_key', 'secondary_access_key'] as $key) { if (empty($data->{$key})) { continue; } diff --git a/tests/src/Unit/Azure/PubSub/PubSubClientFactoryTest.php b/tests/src/Unit/Azure/PubSub/PubSubClientFactoryTest.php index fde80c5a..4c78f6f5 100644 --- a/tests/src/Unit/Azure/PubSub/PubSubClientFactoryTest.php +++ b/tests/src/Unit/Azure/PubSub/PubSubClientFactoryTest.php @@ -20,8 +20,7 @@ class PubSubClientFactoryTest extends UnitTestCase { use ProphecyTrait; /** - * @covers ::create - * @covers \Drupal\helfi_api_base\Azure\PubSub\Settings::__construct + * Tests client construction. */ public function testConstruct() : void { $settings = new Settings( diff --git a/tests/src/Unit/Azure/PubSub/PubSubManagerTest.php b/tests/src/Unit/Azure/PubSub/PubSubManagerTest.php index 6f97d77f..66b56276 100644 --- a/tests/src/Unit/Azure/PubSub/PubSubManagerTest.php +++ b/tests/src/Unit/Azure/PubSub/PubSubManagerTest.php @@ -26,15 +26,14 @@ class PubSubManagerTest extends UnitTestCase { use ProphecyTrait; /** - * Tests joinGroup exceptions. + * Tests initializeClient with invalid joinGroup message. */ - public function testJoinGroupException() : void { + public function testInitializeClientJoinGroupException() : void { $time = $this->prophesize(TimeInterface::class); $time->getCurrentTime()->willReturn(1234); $client = $this->prophesize(Client::class); $client->text('{"type":"joinGroup","group":"local"}')->shouldBeCalledTimes(1); - $client->send(Argument::any())->shouldNotBeCalled(); $client->receive()->willReturn(''); $clientFactory = $this->prophesize(PubSubClientFactoryInterface::class); $clientFactory->create('token') @@ -53,7 +52,39 @@ public function testJoinGroupException() : void { $this->prophesize(LoggerInterface::class)->reveal(), ); $this->expectException(ConnectionException::class); - $this->expectExceptionMessage('Failed to join a group.'); + $this->expectExceptionMessage('Failed to initialize the client.'); + $sut->sendMessage(['test' => 'something']); + } + + /** + * Tests initializeClient with invalid credentials. + */ + public function testInitializeClientInvalidCredentials(): void { + $time = $this->prophesize(TimeInterface::class); + $time->getCurrentTime()->willReturn(1234); + + $client = $this->prophesize(Client::class); + $client->text('{"type":"joinGroup","group":"local"}') + ->shouldBeCalledTimes(1) + ->willThrow(new ConnectionException('Test exception')); + $clientFactory = $this->prophesize(PubSubClientFactoryInterface::class); + $clientFactory->create('token') + ->willReturn($client->reveal()); + + $sut = new PubSubManager( + $clientFactory->reveal(), + $this->prophesize(EventDispatcherInterface::class)->reveal(), + $time->reveal(), + new Settings( + 'hub', + 'local', + 'localhost', + ['token'], + ), + $this->prophesize(LoggerInterface::class)->reveal(), + ); + $this->expectException(ConnectionException::class); + $this->expectExceptionMessage('Test exception'); $sut->sendMessage(['test' => 'something']); } From 04724ee736ef95038a7801ec3d90d26b924695eb Mon Sep 17 00:00:00 2001 From: tuutti Date: Tue, 3 Sep 2024 13:22:13 +0300 Subject: [PATCH 5/5] UHF-10559: Updated documentation --- documentation/pubsub-messaging.md | 32 +++------------------------ src/Drush/Commands/PubSubCommands.php | 6 ++--- 2 files changed, 6 insertions(+), 32 deletions(-) diff --git a/documentation/pubsub-messaging.md b/documentation/pubsub-messaging.md index 9e7588cf..7b819dc4 100644 --- a/documentation/pubsub-messaging.md +++ b/documentation/pubsub-messaging.md @@ -4,10 +4,10 @@ Provides an integration to [Azure's Web PubSub service](https://azure.microsoft. ## Configuration -You must define a [JSON Vault item](/documentation/api-accounts.md#managing-external-api-credentials) to use this feature. The data field should be a JSON string containing `endpoint`, `hub`, `group` and `access_key`: +You must define a [JSON Vault item](/documentation/api-accounts.md#managing-external-api-credentials) to use this feature. The data field should be a JSON string containing `endpoint`, `hub`, `group` and `access_key` and optional `secondary_access_key`: ```json -{"endpoint": "", "hub": "", "group": "", "access_key": ""} +{"endpoint": "", "hub": "", "group": "", "access_key": "", "secondary_access_key": ""} ``` ## Usage @@ -85,34 +85,8 @@ $pubsub_account = [ 'hub' => '', 'group' => '', 'access_key' => '', + 'secondary_access_key' => '', ]), ]; $config['helfi_api_base.api_accounts']['vault'][] = $pubsub_account; ``` - -## Solving pubsub related problems - -If menus or news or other content doesn't update normally, you can verify that the pubsub service is working correctly - -### Artemis is not up on etusivu-instance -- See that frontpage production has artemis pod up and running - -#### If the pod is not running -- See if there is a pipeline to get it up again OR -- Contact HiQ - - -### Pubsub-process is not running -- Go to any production site's cron pod - - run `ps aux`, you should see pubsub related process on the list - -#### If the process is not running -- Short term solution is to run `drush cr` to force the site to fetch new data. -- You can run production deployment to get it running again. - - -### Bad credentials -- Go to any cron pod and look for authorization error - -#### Update the credentials -- Go and update the pubsub-vault credentials diff --git a/src/Drush/Commands/PubSubCommands.php b/src/Drush/Commands/PubSubCommands.php index 8d71ccb7..bb616690 100644 --- a/src/Drush/Commands/PubSubCommands.php +++ b/src/Drush/Commands/PubSubCommands.php @@ -28,11 +28,11 @@ final class PubSubCommands extends DrushCommands { /** * Constructs a new instance. * - * @param \Drupal\helfi_api_base\Azure\PubSub\PubSubManagerInterface $clientManager + * @param \Drupal\helfi_api_base\Azure\PubSub\PubSubManagerInterface $pubSubManager * The PubSub client. */ public function __construct( - private readonly PubSubManagerInterface $clientManager, + private readonly PubSubManagerInterface $pubSubManager, ) { parent::__construct(); } @@ -47,7 +47,7 @@ public function __construct( public function listen() : int { for ($received = 0; $received < self::MAX_MESSAGES; $received++) { try { - $message = $this->clientManager->receive(); + $message = $this->pubSubManager->receive(); $this->io() ->writeln(sprintf('Received message [#%d]: %s', $received, $message)); }