
# Hastighedsbegrænsning

Queuety understøtter hastighedsbegrænsning pr. handler for at undgå overbelastning af eksterne API'er eller andre begrænsede ressourcer. Når en handler har nået sin grænse, lader workers dens jobs blive liggende og henter dem igen, når der er plads i tidsvinduet.

## Angiv en hastighedsgrænse

Anvend en hastighedsgrænse, når du sender et job:

```php
use Queuety\Queuety;

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

De to argumenter er:
1. `$max` - Maksimalt antal tilladte kørsler i perioden
2. `$window` - Periodens varighed i sekunder

En grænse, der angives ved afsendelse, registreres kun i processen PHP, som sender jobbet. En worker, der kører i en separat proces, såsom `wp queuety work`, kan ikke se den. Angiv derfor grænser, der skal gælde på tværs af processer, i handlerens `config()` som vist nedenfor ([#3](https://github.com/inline0/queuety/issues/3)).

## Hastighedsgrænser på handlerniveau

Angiv hastighedsgrænser i handlerens `config()`-metode, så de gælder for hver afsendelse:

```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
        ];
    }
}
```

## Sådan fungerer det

Hastighedsgrænser spores pr. handlernavn. Når et job er hentet, registrerer workeren handlerens grænse (fra dens `config()`) og kontrollerer hastighedsbegrænseren. Hvis handleren har nået sin grænse, lægger workeren straks jobbet tilbage i `pending` uden forsinkelse og uden at bruge et forsøg og venter derefter `QUEUETY_WORKER_SLEEP` sekunder, før den undersøger køen igen. En worker startet med `--once` afslutter i stedet.

Hver worker har en tæller i hukommelsen og opdaterer den hvert 5. sekund ud fra tabellen `queuety_logs`. Den tæller `completed`-logposter for handleren inden for de seneste `$window` sekunder. Da optællingen kommer fra den delte logtabel (og fra den delte cache, hvis en sådan er konfigureret), håndhæves grænser på handlerniveau på tværs af alle worker-processer, ikke kun i én worker. Mislykkede kørsler tæller ikke med i grænsen.

## Programmatisk adgang

Få direkte adgang til hastighedsbegrænseren:

```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()` og `is_limited()` arbejder med begrænseren i den aktuelle proces PHP. Hvis du registrerer en grænse her, ændrer det ikke, hvad en worker, der kører separat, håndhæver.

## Anvendelsesområder

- **Eksterne API-grænser.** Tilpas hastighedsgrænsen til APIs kvote (e.g., OpenAIs 60 RPM).
- **Begrænsning af e-mailafsendelse.** Undgå at sende for mange e-mails på kort tid.
- **Ressourcebeskyttelse.** Begræns CPU-intensive handlers for at undgå, at de tager ressourcer fra andre jobs.
