From 2a3d76fc68df8bbe6d31803df0943b7f6c11bfa2 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 03:24:32 +0000 Subject: [PATCH] fix: ETA calculation returns zero prematurely due to rounding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit O método `getOverallEstimatedTimeRemaining` retornava o tempo restante como zero antes da conclusão real se o progresso arredondado (`$overallProgress >= 100`) atingisse 100%, o que pode acontecer dependendo da precisão configurada (ex: um processo em 100% e outro em 99.4% arredonda para 100% caso `precision = 0`). O patch altera a condição de retorno antecipado para `if ($this->isOverallComplete())`, garantindo que todos os processos estejam em 100%. A taxa de tempo para o overall agora usa a média sem arredondamentos para não perder a precisão nos cálculos, e ambas as funções de ETA (`getEstimatedTimeRemaining` e `getOverallEstimatedTimeRemaining`) agora usam `ceil()` ao invés de `round()` para evitar que o tempo caia de 1 para 0 prematuramente (antes do fim real). O commit também conta com testes de regressão de borda. Co-authored-by: insign <1113045+insign@users.noreply.github.com> --- src/Progressable.php | 18 ++++++++++-------- tests/OverallEtaTest.php | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/Progressable.php b/src/Progressable.php index 4492077..3d01509 100644 --- a/src/Progressable.php +++ b/src/Progressable.php @@ -292,9 +292,7 @@ public function isOverallComplete(): bool { * Get the estimated time remaining in seconds for the overall progress. */ public function getOverallEstimatedTimeRemaining(): ?int { - $overallProgress = $this->getOverallProgress(); - - if ($overallProgress >= 100) { + if ($this->isOverallComplete()) { return 0; } @@ -304,11 +302,15 @@ public function getOverallEstimatedTimeRemaining(): ?int { return null; } + $totalProgress = array_sum(array_column($progressData, 'progress')); + $totalCount = count($progressData); + $unroundedOverallProgress = $totalCount > 0 ? $totalProgress / $totalCount : 0; + $startTimes = array_filter(array_column($progressData, 'start_time'), function ($time) { return $time !== null; }); - if (empty($startTimes) || $overallProgress <= 0) { + if (empty($startTimes) || $unroundedOverallProgress <= 0) { return null; } @@ -319,10 +321,10 @@ public function getOverallEstimatedTimeRemaining(): ?int { return null; } - $rate = $overallProgress / $elapsed; - $remainingProgress = 100 - $overallProgress; + $rate = $unroundedOverallProgress / $elapsed; + $remainingProgress = 100 - $unroundedOverallProgress; - return (int) round($remainingProgress / $rate); + return (int) ceil($remainingProgress / $rate); } /** @@ -352,7 +354,7 @@ public function getEstimatedTimeRemaining(): ?int { $rate = $this->progress / $elapsed; // progress per second $remainingProgress = 100 - $this->progress; - return (int) round($remainingProgress / $rate); + return (int) ceil($remainingProgress / $rate); } /** diff --git a/tests/OverallEtaTest.php b/tests/OverallEtaTest.php index 033ee83..1449237 100644 --- a/tests/OverallEtaTest.php +++ b/tests/OverallEtaTest.php @@ -74,4 +74,31 @@ public function test_overall_eta_is_zero_when_complete(): void { $this->assertEquals(0, $this->getOverallEstimatedTimeRemaining()); } + + public function test_overall_eta_does_not_return_zero_prematurely_due_to_rounding(): void { + Carbon::setTestNow(Carbon::now()); + + $uniqueName = 'test_overall_eta_rounding_'.$this->testId; + $this->setOverallUniqueName($uniqueName); + $this->setLocalKey('process_1'); + $this->setPrecision(0); + $this->setLocalProgress(0); // Set start time + + $obj2 = new class { + use Progressable; + }; + $obj2->setOverallUniqueName($uniqueName); + $obj2->setLocalKey('process_2'); + $obj2->setPrecision(0); + $obj2->setLocalProgress(0); // Set start time + + Carbon::setTestNow(Carbon::now()->addSeconds(10)); + + $this->setLocalProgress(100); + $obj2->setLocalProgress(99.4); + + // Overall progress with precision 0 is round((100+99.4)/2) = round(99.7) = 100 + // It shouldn't return 0 for ETA yet! + $this->assertGreaterThan(0, $this->getOverallEstimatedTimeRemaining()); + } }