Files
trafficpumper/app/Serp/Operations/RampUpPolicy.php
T

42 lines
1.8 KiB
PHP
Raw Normal View History

2026-08-29 15:53:53 +03:00
<?php
namespace App\Serp\Operations;
use App\Models\SerpBudgetEntry;
use App\Models\SerpOperationState;
final class RampUpPolicy
{
public function __construct(private ActivationManager $activation) {}
public function assertAllowsNewPaid(): void
{
if ($this->activation->state() !== ActivationState::Enabled) {
return;
}$state = SerpOperationState::query()->lockForUpdate()->find(1);
if (! $state) {
throw new OperationBlockedException('ramp_state_missing');
}
if (! $state->ramp_started_at) {
$state->forceFill(['ramp_started_at' => now('UTC')])->save();
}$age = $state->ramp_started_at->diffInMinutes(now('UTC'));
$limit = $age < 60 ? (int) config('serp.ramp.first_hour_limit') : ($age < 360 ? (int) config('serp.ramp.six_hour_limit') : (int) config('serp.ramp.first_day_limit'));
$count = SerpBudgetEntry::where('reserved_at', '>=', $state->ramp_started_at)->count();
if ($count >= $limit) {
throw new OperationBlockedException('ramp_up_limit');
}
}
public function status(): array
{
$state = SerpOperationState::find(1);
if (! $state?->ramp_started_at) {
return ['started_at' => null, 'age_minutes' => null, 'used' => 0, 'limit' => (int) config('serp.ramp.first_hour_limit')];
}$age = $state->ramp_started_at->diffInMinutes(now('UTC'));
$limit = $age < 60 ? (int) config('serp.ramp.first_hour_limit') : ($age < 360 ? (int) config('serp.ramp.six_hour_limit') : (int) config('serp.ramp.first_day_limit'));
return ['started_at' => $state->ramp_started_at->toAtomString(), 'age_minutes' => (int) $age, 'used' => SerpBudgetEntry::where('reserved_at', '>=', $state->ramp_started_at)->count(), 'limit' => $limit];
}
}