From b19fe463fe3619300b04827456228c77092128ff Mon Sep 17 00:00:00 2001 From: Baspa Date: Fri, 16 Aug 2024 09:15:11 +0200 Subject: [PATCH] Throttle requests --- README.md | 12 +++++++++++ config/seo.php | 7 +++++- src/Commands/SeoScan.php | 46 +++++++++++++++++++++++++++++++--------- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 04f44b90..f47f19ce 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Easily configure which routes to scan, exclude or include specific checks or eve - [Scanning routes](#scanning-routes) - [Scanning a single route](#scanning-a-single-route) - [Scanning routes in an SPA application](#scanning-routes-in-an-spa-application) + - [Throttling](#throttling) - [Scan model urls](#scan-model-urls) - [Saving scans into the database](#saving-scans-into-the-database) - [Listening to events](#listening-to-events) @@ -186,6 +187,17 @@ php artisan seo:scan-url https://vormkracht10.nl --javascript > Note: This command will use Puppeteer to render the page. Make sure that you have Puppeteer installed on your system. You can install Puppeteer by running the following command: `npm install puppeteer`. **At this moment it's only available when scanning single routes.** +### Throttling + +If you want to throttle the requests, you can set the `throttle` option to `true` in the config file. You can also set the amount of requests per minute by setting the `requests_per_minute` option in the config file. + +```php +'throttle' => [ + 'enabled' => false, + 'requests_per_minute' => 10, +], +``` + ### Scan model urls When you have an application where you have a lot of pages which are related to a model, you can save the SEO score to the model. This way you can check the SEO score of a specific page and show it in your application. diff --git a/config/seo.php b/config/seo.php index 2f2b185b..33597854 100644 --- a/config/seo.php +++ b/config/seo.php @@ -90,6 +90,11 @@ 'vapor-ui/*', ], + 'throttle' => [ + 'enabled' => false, + 'requests_per_minute' => null, + ], + /* |-------------------------------------------------------------------------- | Domains (DNS resolving) @@ -195,4 +200,4 @@ // ], ], -]; +]; \ No newline at end of file diff --git a/src/Commands/SeoScan.php b/src/Commands/SeoScan.php index 62927512..4548b64a 100644 --- a/src/Commands/SeoScan.php +++ b/src/Commands/SeoScan.php @@ -94,26 +94,52 @@ public function handle(): int private function calculateScoreForRoutes(): void { $routes = self::getRoutes(); + $throttleEnabled = config('seo.throttle.enabled'); + $maxRequests = config('seo.throttle.requests_per_minute') ?? 'N/A'; + $requestCount = 0; + $startTime = time(); + + if ($throttleEnabled) { + $this->line('Throttling enabled. Maximum requests per minute: ' . $maxRequests . ''); + sleep(5); + } - $routes->each(function ($path, $name) { + $routes->each(function ($path, $name) use ($throttleEnabled, $maxRequests, &$requestCount, &$startTime) { $this->progress->start(); - $seo = Seo::check(url: route($name), progress: $this->progress, useJavascript: config('seo.javascript')); - - $this->failed += count($seo->getFailedChecks()); - $this->success += count($seo->getSuccessfulChecks()); - $this->routeCount++; + if ($throttleEnabled) { - if (config('seo.database.save')) { - $this->saveScoreToDatabase(seo: $seo, url: route($name)); + if ($requestCount >= $maxRequests) { + $elapsedTime = time() - $startTime; + if ($elapsedTime < 60) { + sleep(60 - $elapsedTime); + } + $requestCount = 0; + $startTime = time(); + } + $requestCount++; } + $this->performSeoCheck($name); $this->progress->finish(); - - $this->logResultToConsole($seo, route($name)); }); } + private function performSeoCheck($name): void + { + $seo = Seo::check(url: route($name), progress: $this->progress, useJavascript: config('seo.javascript')); + + $this->failed += count($seo->getFailedChecks()); + $this->success += count($seo->getSuccessfulChecks()); + $this->routeCount++; + + if (config('seo.database.save')) { + $this->saveScoreToDatabase(seo: $seo, url: route($name)); + } + + $this->logResultToConsole($seo, route($name)); + } + private static function getRoutes(): Collection { $routes = collect(app('router')->getRoutes()->getRoutesByName())