From 4af326e9963e06b57820cc25bcdc4729a2585724 Mon Sep 17 00:00:00 2001 From: William Allen Date: Tue, 4 Aug 2026 15:22:43 -0400 Subject: [PATCH] Don't check build count on every submission CDash currently queries the exact number of builds in a project on every submission. While the query uses a reasonably efficient index scan, it still adds up to substantial database load during peak hours when many submissions are being received around the same time. This PR adds a caching mechanism to skip the check if it's been less than 10 minutes since the previous check. This approach means that the number of builds may briefly exceed the threshold, which seems like an acceptable tradeoff. --- app/cdash/app/Model/Project.php | 10 ++++++++++ app/cdash/tests/test_limitedbuilds.php | 12 ++++++++++-- phpstan-baseline.neon | 6 ++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/cdash/app/Model/Project.php b/app/cdash/app/Model/Project.php index 207f940cc8..41b3e33977 100644 --- a/app/cdash/app/Model/Project.php +++ b/app/cdash/app/Model/Project.php @@ -30,6 +30,7 @@ use DateTimeZone; use Exception; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use PDO; @@ -501,6 +502,15 @@ public function CheckForTooManyBuilds(): bool return false; } + // Fetching the exact build count is expensive, so don't do it if it's been less than + // 10 minutes since the last time we checked. While this means build counts can temporarily + // be higher than the limit, it lightens the database load during peak hours. + $cache_key = "check_too_many_builds_project_{$this->Id}"; + if (Cache::has($cache_key)) { + return false; + } + Cache::put($cache_key, true, 10 * 60); + $project = EloquentProject::findOrFail((int) $this->Id); $num_builds = $project->builds()->onlyParents()->count(); diff --git a/app/cdash/tests/test_limitedbuilds.php b/app/cdash/tests/test_limitedbuilds.php index af8eea1551..aba69ded69 100644 --- a/app/cdash/tests/test_limitedbuilds.php +++ b/app/cdash/tests/test_limitedbuilds.php @@ -9,6 +9,7 @@ use CDash\Database; use CDash\Model\Build; use CDash\Model\Project; +use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\DB; class LimitedBuildsTestCase extends KWWebTestCase @@ -58,14 +59,21 @@ public function testLimitedBuilds(): void $project = App\Models\Project::findOrFail((int) $this->Projects[0]->Id); - // Submit two builds to the 'Limited' project. - // The second submission will cause the first build to get deleted. + // Submit three builds to the 'Limited' project. + // The second submission will not cause the first build to get deleted because it's been + // than 10 minutes since the previous build. Flushing the cache expires the record and + // means submitting the 3rd build will cause the first two to be deleted. $this->submitBuild(1, 'Limited'); $this->assertEqual($project->refresh()->builds()->count(), 1); $this->get_build_stmt->execute([$this->Projects[0]->Id]); $buildid1 = $this->get_build_stmt->fetchColumn(); + $this->submitBuild(2, 'Limited'); + $this->assertEqual($project->refresh()->builds()->count(), 2); + + Cache::flush(); + $this->submitBuild(2, 'Limited'); $this->assertEqual($project->refresh()->builds()->count(), 1); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 5986c258c6..30b41920af 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -9219,6 +9219,12 @@ parameters: count: 1 path: app/cdash/app/Model/Project.php + - + rawMessage: 'Method CDash\Model\Project::CheckForTooManyBuilds() throws checked exception Psr\SimpleCache\InvalidArgumentException but it''s missing from the PHPDoc @throws tag.' + identifier: missingType.checkedException + count: 1 + path: app/cdash/app/Model/Project.php + - rawMessage: 'Method CDash\Model\Project::ComputeTestingDayBounds() has parameter $date with no type specified.' identifier: missingType.parameter