diff --git a/composer.json b/composer.json index 5867305..f498aee 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ }, "require": { "php": ">=8.1", - "utopia-php/telemetry": "0.1.*" + "utopia-php/telemetry": "^0.4.0" }, "require-dev": { "phpunit/phpunit": "^9.3", diff --git a/composer.lock b/composer.lock index cb40d43..a08b170 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c5518a6e1914ae22a3b56aa56ebed804", + "content-hash": "0645b381d7c313486286bcfa6efaf025", "packages": [ { "name": "brick/math", @@ -1810,43 +1810,44 @@ }, { "name": "utopia-php/telemetry", - "version": "0.1.0", + "version": "0.4.6", "source": { "type": "git", "url": "https://github.com/utopia-php/telemetry.git", - "reference": "d35f2f0632f4ee0be63fb7ace6a94a6adda71a80" + "reference": "f96778a01792c32df0876fe1f38a79b9588445d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/telemetry/zipball/d35f2f0632f4ee0be63fb7ace6a94a6adda71a80", - "reference": "d35f2f0632f4ee0be63fb7ace6a94a6adda71a80", + "url": "https://api.github.com/repos/utopia-php/telemetry/zipball/f96778a01792c32df0876fe1f38a79b9588445d8", + "reference": "f96778a01792c32df0876fe1f38a79b9588445d8", "shasum": "" }, "require": { - "ext-opentelemetry": "*", "ext-protobuf": "*", - "nyholm/psr7": "^1.8", - "open-telemetry/exporter-otlp": "^1.1", - "open-telemetry/sdk": "^1.1", + "nyholm/psr7": "1.*", + "open-telemetry/exporter-otlp": "1.*", + "open-telemetry/sdk": "1.*", "php": ">=8.0", - "symfony/http-client": "^7.1" + "symfony/http-client": "7.*" }, "require-dev": { - "laravel/pint": "^1.2", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.5.25" + "swoole/ide-helper": "6.*" + }, + "suggest": { + "ext-sockets": "Required for the Swoole transport implementation", + "ext-swoole": "Required for the Swoole transport implementation" }, "type": "library", "autoload": { "psr-4": { - "Utopia\\": "src/" + "Utopia\\Telemetry\\": "src/Telemetry" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], + "description": "A lite & fast telemetry library, with adapters for OpenTelemetry", "keywords": [ "framework", "php", @@ -1854,9 +1855,9 @@ ], "support": { "issues": "https://github.com/utopia-php/telemetry/issues", - "source": "https://github.com/utopia-php/telemetry/tree/0.1.0" + "source": "https://github.com/utopia-php/telemetry/tree/0.4.6" }, - "time": "2024-11-13T10:29:53+00:00" + "time": "2026-08-05T17:56:48+00:00" } ], "packages-dev": [ @@ -3732,12 +3733,12 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": ">=8.1" }, - "platform-dev": [], - "plugin-api-version": "2.6.0" + "platform-dev": {}, + "plugin-api-version": "2.9.0" } diff --git a/src/Balancer/Balancer.php b/src/Balancer/Balancer.php index c481393..a8aeec2 100644 --- a/src/Balancer/Balancer.php +++ b/src/Balancer/Balancer.php @@ -46,7 +46,16 @@ public function addFilter(callable $filter): self return $this; } - public function run(): ?Option + /** + * Every option that passed all filters, in the order they were added. + * + * `run()` narrows this to one option through the algorithm. Callers that + * have to act on all of them — fanning a request out to every option that + * qualifies, rather than balancing between them — read them here. + * + * @return Option[] + */ + public function getFilteredOptions(): array { $options = $this->options; @@ -54,7 +63,12 @@ public function run(): ?Option $options = \array_filter($options, $filter); } - $options = \array_values($options); + return \array_values($options); + } + + public function run(): ?Option + { + $options = $this->getFilteredOptions(); if (\count($options) === 0) { return null; diff --git a/tests/Balancer/BalancerTest.php b/tests/Balancer/BalancerTest.php index c18df7d..3722a77 100644 --- a/tests/Balancer/BalancerTest.php +++ b/tests/Balancer/BalancerTest.php @@ -244,4 +244,40 @@ public function testGetOptions(): void $this->assertEquals('fra-2', $groupOptions[4]->getState('dataCenter')); $this->assertEquals('lon-1', $groupOptions[5]->getState('dataCenter')); } + + public function testFilteredOptions(): void + { + $balancer = new Balancer(new First()); + + $balancer + ->addOption(new Option(['hostname' => 'worker-1', 'isOnline' => true, 'cpu' => 80])) + ->addOption(new Option(['hostname' => 'worker-2', 'isOnline' => false, 'cpu' => 20])) + ->addOption(new Option(['hostname' => 'worker-3', 'isOnline' => true, 'cpu' => 35])); + + // Unfiltered, every option qualifies + $this->assertCount(3, $balancer->getFilteredOptions()); + + $balancer->addFilter(fn ($option) => $option->getState('isOnline') === true); + + $filtered = $balancer->getFilteredOptions(); + + // All survivors, not just the one the algorithm would pick + $this->assertCount(2, $filtered); + $this->assertEquals('worker-1', $filtered[0]->getState('hostname')); + $this->assertEquals('worker-3', $filtered[1]->getState('hostname')); + $this->assertEquals('worker-1', ($balancer->run() ?? new Option([]))->getState('hostname')); + + $balancer->addFilter(fn ($option) => $option->getState('cpu') < 50); + + $filtered = $balancer->getFilteredOptions(); + + // Filters compose, and the keys are reindexed from zero + $this->assertCount(1, $filtered); + $this->assertEquals('worker-3', $filtered[0]->getState('hostname')); + + $balancer->addFilter(fn ($option) => false); + + $this->assertSame([], $balancer->getFilteredOptions()); + $this->assertNull($balancer->run()); + } }