
# Обмеження частоти

Queuety підтримує обмеження частоти для кожного обробника, щоб запобігти перевантаженню зовнішніх API та інших ресурсів із обмеженою пропускною здатністю. Коли обробник досягає ліміту, робочі процеси залишають його завдання в очікуванні й беруться за них знову, щойно у вікні з’являється вільне місце.

## Налаштування обмеження частоти

Застосуйте обмеження частоти під час надсилання завдання:

```php
use Queuety\Queuety;

Queuety::dispatch( 'call_openai', $payload )
    ->rate_limit( 10, 60 ); // max 10 executions per 60 seconds
```

Два аргументи:
1. `$max` — максимальна кількість виконань у межах вікна
2. `$window` — тривалість вікна в секундах

Обмеження, задане під час надсилання, реєструється лише в процесі PHP, який надсилає завдання. Робочий процес, запущений в окремому процесі, наприклад `wp queuety work`, його не бачить. Тому обмеження, які мають діяти між процесами, потрібно задавати в `config()` обробника, як показано нижче ([#3](https://github.com/inline0/queuety/issues/3)).

## Обмеження частоти на рівні обробника

Задайте обмеження частоти в методі `config()` обробника, щоб вони діяли для кожного надсилання:

```php
use Queuety\Handler;

class CallOpenAIHandler implements Handler {
    public function handle( array $payload ): void {
        // Call the API...
    }

    public function config(): array {
        return [
            'rate_limit' => [ 60, 60 ], // 60 requests per minute
        ];
    }
}
```

## Як це працює

Обмеження частоти відстежуються окремо для кожного імені обробника. Отримавши завдання, робочий процес реєструє ліміт обробника (з його `config()`) і перевіряє засіб обмеження частоти. Якщо обробник досяг ліміту, робочий процес одразу повертає завдання до `pending` без затримки й без витрати спроби, а потім чекає `QUEUETY_WORKER_SLEEP` секунд перед наступним опитуванням. Натомість робочий процес, запущений з `--once`, завершується.

Кожен робочий процес зберігає лічильник у пам’яті й оновлює його кожні 5 секунд на основі таблиці `queuety_logs`, підраховуючи записи журналу `completed` для обробника за останні `$window` секунд. Оскільки підрахунок ведеться за спільною таблицею журналів (і спільним кешем, якщо його налаштовано), обмеження на рівні обробника діють для всіх процесів робочих процесів, а не лише в межах одного. Невдалі виконання не враховуються в ліміті.

## Програмний доступ

Отримайте прямий доступ до засобу обмеження частоти:

```php
$limiter = Queuety::rate_limiter();

// Register a rate limit
$limiter->register( 'call_openai', 60, 60 );

// Check whether a handler has reached its limit
$limited = $limiter->is_limited( 'call_openai' ); // true while the limit is reached

// Seconds until the current window resets
$wait = $limiter->time_until_available( 'call_openai' );
```

`register()` і `is_limited()` працюють із засобом обмеження в поточному процесі PHP. Реєстрація обмеження тут не змінює правил, яких дотримується окремо запущений робочий процес.

## Варіанти використання

- **Обмеження зовнішніх API.** Узгодьте ліміт частоти з квотою API (e.g., 60 RPM від OpenAI).
- **Обмеження надсилання електронних листів.** Запобігайте надсиланню надто великої кількості листів за короткий проміжок часу.
- **Захист ресурсів.** Обмежуйте обробники, що інтенсивно використовують CPU, щоб вони не позбавляли інші завдання ресурсів.
