Files
2026-08-04 17:09:39 +02:00

64 lines
2.1 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\WebhookEndpoint;
use App\Models\WebhookRequest;
use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Carbon;
#[Signature('webhooks:prune')]
#[Description('Remove expired endpoints and old webhook requests')]
class PruneWebhookData extends Command
{
public function handle(): int
{
$now = now();
$deletedRequests = WebhookRequest::query()
->where('received_at', '<', $now->copy()->subDays((int) config('webhooks.request_retention_days', 7)))
->delete();
$this->pruneEndpointLimits();
$deletedEndpoints = $this->deleteExpiredAnonymousEndpoints($now);
$this->info("Deleted {$deletedRequests} old requests and {$deletedEndpoints} expired endpoints.");
return self::SUCCESS;
}
private function pruneEndpointLimits(): void
{
WebhookEndpoint::query()
->select('id')
->chunkById(100, function (Collection $endpoints): void {
foreach ($endpoints as $endpoint) {
$requestIds = WebhookRequest::query()
->whereBelongsTo($endpoint, 'endpoint')
->select('id')
->orderByDesc('received_at')
->orderByDesc('id')
->skip((int) config('webhooks.max_requests_per_endpoint', 1000))
->take(1_000_000_000)
->pluck('id');
if ($requestIds->isNotEmpty()) {
WebhookRequest::query()->whereKey($requestIds)->delete();
}
}
});
}
private function deleteExpiredAnonymousEndpoints(Carbon $now): int
{
return WebhookEndpoint::query()
->public()
->whereNull('user_id')
->whereNotNull('expires_at')
->where('expires_at', '<', $now)
->delete();
}
}