From 7522f8db3124d486bf8b985672483567c20fbdca Mon Sep 17 00:00:00 2001 From: dmitry krokhin Date: Tue, 24 Dec 2024 14:43:03 +0300 Subject: [PATCH] service response types --- src/Service/Response/Info.php | 31 +++++++++ src/Service/Response/Ping.php | 15 ++++ src/Service/Response/Stats.php | 36 ++++++++++ src/Service/Service.php | 116 ++++++++----------------------- src/Service/ServiceGroup.php | 10 +-- tests/Functional/ServiceTest.php | 92 +++++++++++++++++------- 6 files changed, 178 insertions(+), 122 deletions(-) create mode 100644 src/Service/Response/Info.php create mode 100644 src/Service/Response/Ping.php create mode 100644 src/Service/Response/Stats.php diff --git a/src/Service/Response/Info.php b/src/Service/Response/Info.php new file mode 100644 index 0000000..b2c8055 --- /dev/null +++ b/src/Service/Response/Info.php @@ -0,0 +1,31 @@ + */ + array $endpoints, + ) { + $this->endpoints = array_map(self::collect(...), $endpoints); + } + + public static function collect(ServiceEndpoint $endpoint): array + { + return [ + 'name' => $endpoint->getName(), + 'subject' => $endpoint->getSubject(), + 'queue_group' => $endpoint->getQueueGroup(), + ]; + } +} diff --git a/src/Service/Response/Ping.php b/src/Service/Response/Ping.php new file mode 100644 index 0000000..bed7a54 --- /dev/null +++ b/src/Service/Response/Ping.php @@ -0,0 +1,15 @@ + */ + array $endpoints, + ) { + $this->endpoints = array_values(array_map(self::collect(...), $endpoints)); + } + + public static function collect(ServiceEndpoint $endpoint): array + { + return [ + 'name' => $endpoint->getName(), + 'subject' => $endpoint->getSubject(), + 'queue_group' => $endpoint->getQueueGroup(), + 'num_requests' => $endpoint->getNumRequests(), + 'num_errors' => $endpoint->getNumErrors(), + 'last_error' => $endpoint->getLastError(), + 'processing_time' => $endpoint->getProcessingTime(), + 'average_processing_time' => $endpoint->getAverageProcessingTime(), + ]; + } +} diff --git a/src/Service/Service.php b/src/Service/Service.php index 0022a38..4d6123a 100644 --- a/src/Service/Service.php +++ b/src/Service/Service.php @@ -3,51 +3,35 @@ namespace Basis\Nats\Service; use Basis\Nats\Client; -use Basis\Nats\Message\Payload; +use Basis\Nats\Service\Response\Info; +use Basis\Nats\Service\Response\Ping; +use Basis\Nats\Service\Response\Stats; class Service { - public Client $client; - private string $id; - - private string $name; - - private string $description = ''; - - private string $version; - private string $started; + /** @var array */ private array $endpoints = []; - private array $groups = []; - private array $subscriptions = []; public function __construct( - Client $client, - string $name, - string $description = 'Default Description', - string $version = '0.0.1' + public Client $client, + private string $name, + private string $description = 'Default Description', + private string $version = '0.0.1' ) { - $this->client = $client; $this->id = $this->generateId(); - $this->name = $name; - $this->description = $description; - $this->version = $version; $this->started = date("Y-m-d\TH:i:s.v\Z"); - - // Register the service verbs to listen for $this->registerVerbs(); } private function generateId(): string { $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - $charactersLength = strlen($characters); - $randomString = ""; for ($i = 0; $i < 22; $i++) { @@ -59,59 +43,29 @@ private function generateId(): string private function ping(): array { - return [ - 'type' => 'io.nats.micro.v1.ping_response', - 'name' => $this->name, - 'id' => $this->id, - 'version' => $this->version, - ]; + return (array) new Ping($this->name, $this->id, $this->version); } private function info(): array { - $endpoints = []; - - foreach ($this->endpoints as $endpoint) { - $endpoints[] = [ - 'name' => $endpoint->getName(), - 'subject' => $endpoint->getSubject(), - 'queue_group' => $endpoint->getQueueGroup(), - ]; - } - - return [ - 'type' => 'io.nats.micro.v1.info_response', - 'name' => $this->name, - 'id' => $this->id, - 'version' => $this->version, - 'description' => $this->description, - 'endpoints' => $endpoints - ]; + return (array) new Info( + name: $this->name, + id: $this->id, + version: $this->version, + description: $this->description, + endpoints: $this->endpoints, + ); } private function stats(): array { - return [ - 'type' => 'io.nats.micro.v1.stats_response', - 'name' => $this->name, - 'id' => $this->id, - 'version' => $this->version, - 'endpoints' => array_reduce($this->endpoints, function ($carry, ServiceEndpoint $endpoint) { - $carry[] = [ - 'name' => $endpoint->getName(), - 'subject' => $endpoint->getSubject(), - 'queue_group' => $endpoint->getQueueGroup(), - 'num_requests' => $endpoint->getNumRequests(), - 'num_errors' => $endpoint->getNumErrors(), - 'last_error' => $endpoint->getLastError(), - 'processing_time' => $endpoint->getProcessingTime(), - 'average_processing_time' => $endpoint->getAverageProcessingTime(), - ]; - - return $carry; - }, []), - 'started' => $this->started, - ]; + return (array) new Stats( + name: $this->name, + id: $this->id, + version: $this->version, + started: $this->started, + endpoints: $this->endpoints, + ); } public function addGroup(string $name): ServiceGroup @@ -143,13 +97,7 @@ public function addEndpoint( throw new \LogicException("Endpoint $name already is defined"); } - $this->endpoints[$name] = new ServiceEndpoint( - $this, - $name, - $subject, - $endpointHandler, - $queue_group - ); + $this->endpoints[$name] = new ServiceEndpoint($this, $name, $subject, $endpointHandler, $queue_group); } public function reset(): void @@ -165,15 +113,9 @@ function (ServiceEndpoint $endpoint) { private function registerVerbs(): void { $verbs = [ - 'PING' => function (Payload $payload) { - return $this->ping(); - }, - 'INFO' => function (Payload $payload) { - return $this->info(); - }, - 'STATS' => function (Payload $payload) { - return $this->stats(); - }, + 'PING' => $this->ping(...), + 'INFO' => $this->info(...), + 'STATS' => $this->stats(...), ]; foreach ($verbs as $verb => $handler) { @@ -218,9 +160,7 @@ private function controlSubject(string $verb, string $name, string $id): string public function run(): void { - $this->client - ->logger - ->info("$this->name is ready to accept connections\n"); + $this->client->logger->info("$this->name is ready to accept connections\n"); while (true) { try { diff --git a/src/Service/ServiceGroup.php b/src/Service/ServiceGroup.php index a4e85f6..8f6c411 100644 --- a/src/Service/ServiceGroup.php +++ b/src/Service/ServiceGroup.php @@ -32,12 +32,8 @@ public function addEndpoint( $subject = $this->name . '.' . $options['subject']; } - $this->service->addEndpoint( - $name, - $serviceHandler, - [ - 'subject' => $subject, - ] - ); + $this->service->addEndpoint($name, $serviceHandler, [ + 'subject' => $subject, + ]); } } diff --git a/tests/Functional/ServiceTest.php b/tests/Functional/ServiceTest.php index 35a10ff..32ac74b 100644 --- a/tests/Functional/ServiceTest.php +++ b/tests/Functional/ServiceTest.php @@ -24,21 +24,71 @@ private function createTestService(): Service return $service; } + + public function testServiceInfo() + { + $service = $this->createTestService(); + $service->addGroup('v1')->addEndpoint('test_info', TestEndpoint::class); + + $service->client->publish('$SRV.INFO', ''); + $info = $service->client->process(1); + + $this->assertIsArray($info); + $this->assertArrayHasKey('type', $info); + $this->assertSame($info['type'], 'io.nats.micro.v1.info_response'); + $this->assertSame($info['name'], 'TestService'); + + $this->assertCount(1, $info['endpoints']); + $this->assertSame("v1.test_info", $info['endpoints']['test_info']['subject']); + } + + public function testServicePing() + { + $service = $this->createTestService(); + + $service->addGroup('v1')->addEndpoint('test_ping', TestEndpoint::class); + + $service->client->publish('$SRV.PING', ''); + $ping = $service->client->process(1); + + $this->assertIsArray($ping); + $this->assertArrayHasKey('type', $ping); + $this->assertSame($ping['type'], 'io.nats.micro.v1.ping_response'); + $this->assertSame($ping['name'], 'TestService'); + } + + public function testServiceStats() + { + $service = $this->createTestService(); + + $service->addGroup('v1')->addEndpoint('test_stats', TestEndpoint::class); + + $service->client->publish('$SRV.STATS', ''); + $stats = $service->client->process(1); + + $this->assertIsArray($stats); + $this->assertArrayHasKey('type', $stats); + $this->assertSame($stats['type'], 'io.nats.micro.v1.stats_response'); + $this->assertSame($stats['name'], 'TestService'); + + $this->assertSame($stats['endpoints'][0]['average_processing_time'], 0.0); + + $service->client->publish('v1.test_stats', ''); + $service->client->process(1); + + $service->client->publish('$SRV.STATS', ''); + $stats = $service->client->process(1); + $this->assertNotSame($stats['endpoints'][0]['average_processing_time'], 0.0); + } + public function testServiceRequestReplyClass() { $service = $this->createTestService(); - $service - ->addGroup('v1') - ->addEndpoint( - 'test_class', - TestEndpoint::class - ); + $service->addGroup('v1')->addEndpoint('test_class', TestEndpoint::class); $service->client->publish('v1.test_class', ''); - $response = $service->client->process(1); - $this->assertTrue($response['success']); } @@ -46,17 +96,12 @@ public function testServiceRequestReplyCallable() { $service = $this->createTestService(); - $service - ->addGroup('v1') - ->addEndpoint( - 'test_callback', - function (Payload $payload) { - return [ - 'success' => true, - 'nick' => $payload->getValue('nick'), - ]; - } - ); + $service->addGroup('v1')->addEndpoint('test_callback', function (Payload $payload) { + return [ + 'success' => true, + 'nick' => $payload->getValue('nick'), + ]; + }); $service->client->publish('v1.test_callback', ['nick' => 'nekufa']); $response = $service->client->process(1); @@ -69,17 +114,10 @@ public function testServiceRequestReplyInstance() { $service = $this->createTestService(); - $service - ->addGroup('v1') - ->addEndpoint( - 'test_instance', - new TestEndpoint() - ); + $service->addGroup('v1')->addEndpoint('test_instance', new TestEndpoint()); $service->client->publish('v1.test_instance', ''); - $response = $service->client->process(1); - $this->assertTrue($response['success']); } }