From a17b9ab60ce2d35bfa9dcd5a88873f7b846d0e87 Mon Sep 17 00:00:00 2001 From: nckrtl Date: Mon, 20 Oct 2025 16:42:42 +0200 Subject: [PATCH 1/8] Bug fix --- src/ProcessPool.php | 4 ++-- tests/Feature/AutoScalerTest.php | 21 +++++++++++++++++++++ tests/Feature/Fakes/FakePool.php | 11 ++++++++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/ProcessPool.php b/src/ProcessPool.php index 97672917..4af7da5b 100644 --- a/src/ProcessPool.php +++ b/src/ProcessPool.php @@ -303,13 +303,13 @@ public function runningProcesses() } /** - * Get the total active process count, including processes pending termination. + * Get the total process count * * @return int */ public function totalProcessCount() { - return count($this->processes()) + count($this->terminatingProcesses); + return count($this->processes()); } /** diff --git a/tests/Feature/AutoScalerTest.php b/tests/Feature/AutoScalerTest.php index 7a4c98e5..e16a6cc7 100644 --- a/tests/Feature/AutoScalerTest.php +++ b/tests/Feature/AutoScalerTest.php @@ -288,4 +288,25 @@ public function test_scaler_works_with_a_single_process_pool() $this->assertSame(6, $supervisor->processPools['default']->totalProcessCount()); } + + public function test_scaler_calculates_available_capacity_correctly() + { + [$scaler, $supervisor] = $this->with_scaling_scenario(5, [ + 'first' => ['current' => 3, 'size' => 0, 'runtime' => 0], + 'second' => ['current' => 1, 'size' => 100, 'runtime' => 100], + ]); + + // Simulate terminating process on first queue scaling down from previous work + $supervisor->processPools['first']->terminatingProcessCount = 1; + + $scaler->scale($supervisor); + + $this->assertSame(2, $supervisor->processPools['first']->processCount); + $this->assertSame(2, $supervisor->processPools['second']->processCount); + + $scaler->scale($supervisor); + + $this->assertSame(1, $supervisor->processPools['first']->processCount); + $this->assertSame(3, $supervisor->processPools['second']->processCount); + } } diff --git a/tests/Feature/Fakes/FakePool.php b/tests/Feature/Fakes/FakePool.php index 5ed7482d..f2504c20 100644 --- a/tests/Feature/Fakes/FakePool.php +++ b/tests/Feature/Fakes/FakePool.php @@ -6,11 +6,13 @@ class FakePool { public $queue; public $processCount; + public $terminatingProcessCount; - public function __construct($queue, $processCount) + public function __construct($queue, $processCount, $terminatingProcessCount = 0) { $this->queue = $queue; $this->processCount = $processCount; + $this->terminatingProcessCount = $terminatingProcessCount; } public function scale($processCount) @@ -32,4 +34,11 @@ public function totalProcessCount() { return $this->processCount; } + + public function processes() + { + return array_fill(0, $this->processCount, null); + } + + public $terminatingProcesses = []; } From 83eacb687d6886815bf3a7412cad3269a345b1e3 Mon Sep 17 00:00:00 2001 From: nckrtl Date: Mon, 20 Oct 2025 16:56:52 +0200 Subject: [PATCH 2/8] Cleanup ProcessPool --- src/ProcessPool.php | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/ProcessPool.php b/src/ProcessPool.php index 4af7da5b..f2f460e5 100644 --- a/src/ProcessPool.php +++ b/src/ProcessPool.php @@ -4,10 +4,9 @@ use Carbon\CarbonImmutable; use Closure; -use Countable; use Symfony\Component\Process\Process; -class ProcessPool implements Countable +class ProcessPool { /** * All of the active processes. @@ -303,13 +302,13 @@ public function runningProcesses() } /** - * Get the total process count + * Get the total process count. * * @return int */ public function totalProcessCount() { - return count($this->processes()); + return count($this->processes); } /** @@ -321,14 +320,4 @@ public function queue() { return $this->options->queue; } - - /** - * Count the total number of processes in the pool. - * - * @return int - */ - public function count(): int - { - return count($this->processes); - } } From 8bd33a81a5892c87e3b9a5960120d0904dbf76da Mon Sep 17 00:00:00 2001 From: nckrtl Date: Mon, 20 Oct 2025 20:55:31 +0200 Subject: [PATCH 3/8] Use totalProcessCount() for consistency --- src/ProcessPool.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ProcessPool.php b/src/ProcessPool.php index f2f460e5..1cfec72f 100644 --- a/src/ProcessPool.php +++ b/src/ProcessPool.php @@ -69,11 +69,11 @@ public function scale($processes) { $processes = max(0, (int) $processes); - if ($processes === count($this->processes)) { + if ($processes === $this->totalProcessCount()) { return; } - if ($processes > count($this->processes)) { + if ($processes > $this->totalProcessCount()) { $this->scaleUp($processes); } else { $this->scaleDown($processes); From cd9c2f7b0a5cf5c73d75d3d1d0b174e317140ffe Mon Sep 17 00:00:00 2001 From: nckrtl Date: Sat, 25 Oct 2025 16:09:34 +0200 Subject: [PATCH 4/8] Undo changes --- src/AutoScaler.php | 4 ++-- src/ProcessPool.php | 21 ++++++++++++++++----- tests/Feature/AutoScalerTest.php | 21 --------------------- tests/Feature/Fakes/FakePool.php | 11 +---------- 4 files changed, 19 insertions(+), 38 deletions(-) diff --git a/src/AutoScaler.php b/src/AutoScaler.php index b8c5e35a..703659db 100644 --- a/src/AutoScaler.php +++ b/src/AutoScaler.php @@ -147,10 +147,10 @@ protected function scalePool(Supervisor $supervisor, $pool, $workers) { $supervisor->pruneTerminatingProcesses(); - $totalProcessCount = $pool->totalProcessCount(); - $desiredProcessCount = ceil($workers); + $totalProcessCount = $pool->totalProcessCount(); + if ($desiredProcessCount > $totalProcessCount) { $maxUpShift = min( max(0, $supervisor->options->maxProcesses - $supervisor->totalProcessCount()), diff --git a/src/ProcessPool.php b/src/ProcessPool.php index 1cfec72f..97672917 100644 --- a/src/ProcessPool.php +++ b/src/ProcessPool.php @@ -4,9 +4,10 @@ use Carbon\CarbonImmutable; use Closure; +use Countable; use Symfony\Component\Process\Process; -class ProcessPool +class ProcessPool implements Countable { /** * All of the active processes. @@ -69,11 +70,11 @@ public function scale($processes) { $processes = max(0, (int) $processes); - if ($processes === $this->totalProcessCount()) { + if ($processes === count($this->processes)) { return; } - if ($processes > $this->totalProcessCount()) { + if ($processes > count($this->processes)) { $this->scaleUp($processes); } else { $this->scaleDown($processes); @@ -302,13 +303,13 @@ public function runningProcesses() } /** - * Get the total process count. + * Get the total active process count, including processes pending termination. * * @return int */ public function totalProcessCount() { - return count($this->processes); + return count($this->processes()) + count($this->terminatingProcesses); } /** @@ -320,4 +321,14 @@ public function queue() { return $this->options->queue; } + + /** + * Count the total number of processes in the pool. + * + * @return int + */ + public function count(): int + { + return count($this->processes); + } } diff --git a/tests/Feature/AutoScalerTest.php b/tests/Feature/AutoScalerTest.php index e16a6cc7..7a4c98e5 100644 --- a/tests/Feature/AutoScalerTest.php +++ b/tests/Feature/AutoScalerTest.php @@ -288,25 +288,4 @@ public function test_scaler_works_with_a_single_process_pool() $this->assertSame(6, $supervisor->processPools['default']->totalProcessCount()); } - - public function test_scaler_calculates_available_capacity_correctly() - { - [$scaler, $supervisor] = $this->with_scaling_scenario(5, [ - 'first' => ['current' => 3, 'size' => 0, 'runtime' => 0], - 'second' => ['current' => 1, 'size' => 100, 'runtime' => 100], - ]); - - // Simulate terminating process on first queue scaling down from previous work - $supervisor->processPools['first']->terminatingProcessCount = 1; - - $scaler->scale($supervisor); - - $this->assertSame(2, $supervisor->processPools['first']->processCount); - $this->assertSame(2, $supervisor->processPools['second']->processCount); - - $scaler->scale($supervisor); - - $this->assertSame(1, $supervisor->processPools['first']->processCount); - $this->assertSame(3, $supervisor->processPools['second']->processCount); - } } diff --git a/tests/Feature/Fakes/FakePool.php b/tests/Feature/Fakes/FakePool.php index f2504c20..5ed7482d 100644 --- a/tests/Feature/Fakes/FakePool.php +++ b/tests/Feature/Fakes/FakePool.php @@ -6,13 +6,11 @@ class FakePool { public $queue; public $processCount; - public $terminatingProcessCount; - public function __construct($queue, $processCount, $terminatingProcessCount = 0) + public function __construct($queue, $processCount) { $this->queue = $queue; $this->processCount = $processCount; - $this->terminatingProcessCount = $terminatingProcessCount; } public function scale($processCount) @@ -34,11 +32,4 @@ public function totalProcessCount() { return $this->processCount; } - - public function processes() - { - return array_fill(0, $this->processCount, null); - } - - public $terminatingProcesses = []; } From 551e1736c81bc3543f74bdbdc2826091db9f7cbe Mon Sep 17 00:00:00 2001 From: nckrtl Date: Sat, 25 Oct 2025 16:49:21 +0200 Subject: [PATCH 5/8] Include the terminating processes count based on the desired process count --- src/AutoScaler.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/AutoScaler.php b/src/AutoScaler.php index 703659db..97ceaacf 100644 --- a/src/AutoScaler.php +++ b/src/AutoScaler.php @@ -149,7 +149,11 @@ protected function scalePool(Supervisor $supervisor, $pool, $workers) $desiredProcessCount = ceil($workers); - $totalProcessCount = $pool->totalProcessCount(); + $totalProcessCount = $pool->processes()->count(); + + if($desiredProcessCount > $totalProcessCount) { + $totalProcessCount += $pool->terminatingProcesses()->count(); + } if ($desiredProcessCount > $totalProcessCount) { $maxUpShift = min( From 7cc5b48cfa6bef2bede37e103ce67c0f6865df17 Mon Sep 17 00:00:00 2001 From: nckrtl Date: Sat, 25 Oct 2025 16:50:22 +0200 Subject: [PATCH 6/8] undo repositioning of setting $totalProcessCount --- src/AutoScaler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AutoScaler.php b/src/AutoScaler.php index 97ceaacf..6f45fb1f 100644 --- a/src/AutoScaler.php +++ b/src/AutoScaler.php @@ -147,10 +147,10 @@ protected function scalePool(Supervisor $supervisor, $pool, $workers) { $supervisor->pruneTerminatingProcesses(); - $desiredProcessCount = ceil($workers); - $totalProcessCount = $pool->processes()->count(); + $desiredProcessCount = ceil($workers); + if($desiredProcessCount > $totalProcessCount) { $totalProcessCount += $pool->terminatingProcesses()->count(); } From 811675d281bd56201d5a8f236faeb3a2e7268ef9 Mon Sep 17 00:00:00 2001 From: nckrtl Date: Sat, 25 Oct 2025 16:51:59 +0200 Subject: [PATCH 7/8] add style fix --- src/AutoScaler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AutoScaler.php b/src/AutoScaler.php index 6f45fb1f..791b4b2e 100644 --- a/src/AutoScaler.php +++ b/src/AutoScaler.php @@ -151,7 +151,7 @@ protected function scalePool(Supervisor $supervisor, $pool, $workers) $desiredProcessCount = ceil($workers); - if($desiredProcessCount > $totalProcessCount) { + if ($desiredProcessCount > $totalProcessCount) { $totalProcessCount += $pool->terminatingProcesses()->count(); } From 701842461f2eeedfe17394882fd4028941a5bcb0 Mon Sep 17 00:00:00 2001 From: nckrtl Date: Sat, 25 Oct 2025 16:59:15 +0200 Subject: [PATCH 8/8] fix tests --- src/AutoScaler.php | 2 +- tests/Feature/Fakes/FakePool.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/AutoScaler.php b/src/AutoScaler.php index 791b4b2e..c597a9db 100644 --- a/src/AutoScaler.php +++ b/src/AutoScaler.php @@ -152,7 +152,7 @@ protected function scalePool(Supervisor $supervisor, $pool, $workers) $desiredProcessCount = ceil($workers); if ($desiredProcessCount > $totalProcessCount) { - $totalProcessCount += $pool->terminatingProcesses()->count(); + $totalProcessCount = $pool->totalProcessCount(); } if ($desiredProcessCount > $totalProcessCount) { diff --git a/tests/Feature/Fakes/FakePool.php b/tests/Feature/Fakes/FakePool.php index 5ed7482d..051eed1d 100644 --- a/tests/Feature/Fakes/FakePool.php +++ b/tests/Feature/Fakes/FakePool.php @@ -32,4 +32,9 @@ public function totalProcessCount() { return $this->processCount; } + + public function processes() + { + return collect(range(1, $this->processCount)); + } }