
# Workers

Workers er langvarige processer, der afsøger databasen for ventende jobs, udfører dem og fører workflows videre. Kommandoen `wp queuety work` kører inde i WP-CLI, mens selve køen gøres krav på direkte fra MySQL via den bedst tilgængelige Queuety-database-driver.

Pluginet installerer også en standardfallback med WordPress cron, der kører én gang i minuttet, til miljøer uden shell-adgang. Denne side handler om dedikerede WP-CLI-workers, som er den anbefalede udrulningsmetode til højere gennemløb.

## Start en worker

```bash
wp queuety work
```

Dette starter én worker på `default`-køen. Den kører i en løkke: gør krav på et job, udfør det, gentag. Når køen er tom, venter den `QUEUETY_WORKER_SLEEP` sekunder (standard: 1), før den afsøger køen igen.

### Indstillinger

| Valgmulighed | Beskrivelse |
|---|---|
| `--queue=<queue>` | Queue(s), der skal behandles, kommasepareret for at angive prioritetsrækkefølgen (standard: `default`) |
| `--once` | Behandl højst ét job, og afslut |
| `--workers=<n>` | Opret N worker-processer (kræver udvidelserne `pcntl` og `posix`) |
| `--min-workers=<n>` | Minimum antal workers for en tilpasningsdygtig pool. Kræver `--max-workers` |
| `--max-workers=<n>` | Maksimum antal workers for en tilpasningsdygtig pool |

```bash
# Process a specific queue
wp queuety work --queue=emails

# Process at most one job and exit
wp queuety work --once

# Run 4 concurrent workers
wp queuety work --workers=4

# Scale between 2 and 6 workers as backlog changes
wp queuety work --queue=providers --min-workers=2 --max-workers=6
```

## Prioriteter for flere køer

En enkelt worker kan behandle flere køer i prioritetsrækkefølge. Angiv en kommasepareret liste med kønavne til `--queue`:

```bash
wp queuety work --queue=critical,default,low
```

Workeren forsøger at hente et job fra hver kø i den angivne rækkefølge. Den tjekker `critical` først. Hvis `critical` har et job, behandler den jobbet. Hvis `critical` er tom, går den videre til `default` og derefter til `low`. Det betyder, at køer med højere prioritet altid tømmes før køer med lavere prioritet.

### Sådan fungerer prioritetsrækkefølgen

Ved hver gennemløb forsøger workeren at hente et job fra den første kø på listen. Hvis køen er tom eller sat på pause, går den videre til den næste kø og fortsætter, indtil den finder et job eller har gennemgået hele listen. Hvis der ikke findes et job nogen steder, venter workeren og prøver igen. Dette er en streng prioritetsmodel, hvilket betyder, at en konstant strøm af `critical`-jobs vil udsulte `default` og `low`. Brug dedikerede workers, hvis køer med lavere prioritet skal sikres gennemløb.

### Brug af flere køer i PHP

Metoderne `Worker::run()` og `Worker::flush()` accepterer enten en streng eller et array:

```php
// Comma-separated string
Queuety::worker()->run( 'critical,default,low' );

// Array
Queuety::worker()->run( [ 'critical', 'default', 'low' ] );

// flush() also supports multi-queue
$count = Queuety::worker()->flush( 'critical,default,low' );
```

### Udrulningsstrategier

**Dedikerede workers pr. kø** giver fuld kontrol over samtidighed og isolation. Hver kø får sin egen worker-process(es) og kan ikke blive udsultet af andre køer:

```ini
[program:queuety-critical]
command=wp queuety work --queue=critical
numprocs=4

[program:queuety-default]
command=wp queuety work --queue=default
numprocs=2

[program:queuety-low]
command=wp queuety work --queue=low
numprocs=1
```

**Prioritetsrækkefølge med én worker** er enklere at administrere og fungerer godt, når køer med lavere prioritet kan tåle forsinkelser:

```ini
[program:queuety-worker]
command=wp queuety work --queue=critical,default,low
numprocs=2
```

Du kan også kombinere de to metoder: dedikerede workers for `critical` for at sikre gennemløb samt en worker med prioritetsrækkefølge for alt andet:

```ini
[program:queuety-critical]
command=wp queuety work --queue=critical
numprocs=2

[program:queuety-fallback]
command=wp queuety work --queue=default,low
numprocs=2
```

## Ressourcebaseret optagelse

Workers gør mere end blot at hente den næste ventende række. Før et hentet job starter, kan Queuety udføre overordnede optagelseskontroller baseret på jobbets samtidighedsgruppe og handlerens seneste eksekveringsprofil.

Se [Ressourcestyring](https://queuety.inline0.dev/da/docs/features/resource-management) for den overordnede model, herunder hvordan den hænger sammen med jobmetadata og workflowbudgetter.

En samtidighedsgruppe giver flere handlers eller jobklasser en fælles grænse. Hvis du markerer flere ressourcekrævende udbydere med samme gruppe og grænse, frigiver en worker nyligt hentet arbejde i stedet for at starte det, når gruppen har nået sin grænse. Det forhindrer uafhængige køer i at overbelaste det samme downstream-system, blot fordi flere workers er ledige.

Seneste eksekveringslogfiler indgår også i en enkel optagelsesprofil. Når ressourceoptagelse er aktiveret, ser Queuety på den seneste gennemsnitlige varighed og maksimale hukommelsesbrug for den handler, der skal køres. Hvis den aktuelle worker allerede er tæt på sin konfigurerede hukommelsesgrænse, en kø eller udbydergruppe allerede har nået sit vægtede budget, den aktuelle container ikke ser ud til at have nok ledig hukommelse til handlerens observerede profil, eller en kørsel af typen `--once` er tæt på sin tidsgrænse, udsætter Queuety jobbet i stedet for at starte arbejde, der næppe afsluttes korrekt.

Du tilvælger politikken i arbejdsdefinitionen i stedet for i worker-kommandoen:

```php
class CallProviderStep implements \Queuety\Step {
    public function handle( array $state ): array {
        // ...
    }

    public function config(): array {
        return [
            'concurrency_group' => 'providers',
            'concurrency_limit' => 3,
            'cost_units' => 5,
        ];
    }
}
```

De samme metadata kan knyttes til jobklasser, der kan afsendes, via offentlige egenskaber eller til en enkelt afsendelse gennem `PendingJob::concurrency_group()` og `PendingJob::cost_units()`.

Workerens optagelsesprofil styres af disse konstanter:

| Konstant | Beskrivelse |
|---|---|
| `QUEUETY_RESOURCE_ADMISSION` | Aktivér eller deaktiver profilbaserede optagelseskontroller |
| `QUEUETY_RESOURCE_PROFILE_WINDOW_MINUTES` | Hvor langt tilbage der kigges ved opbygning af handlerprofiler baseret på nylige kørsler |
| `QUEUETY_RESOURCE_PROFILE_TTL` | Cache-TTL for handlerprofiler baseret på nylige kørsler |
| `QUEUETY_RESOURCE_MEMORY_HEADROOM_MB` | Reserveret hukommelsesmargin, før endnu et job optages |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS` | Aktivér eller deaktiver bedst mulige hukommelseskontroller for container eller vært |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_HEADROOM_MB` | Reserveret systemhukommelsesmargin, før endnu et job optages |
| `QUEUETY_RESOURCE_QUEUE_COST_BUDGETS` | Vægtede omkostningsbudgetter efter kønavn |
| `QUEUETY_RESOURCE_GROUP_COST_BUDGETS` | Vægtede omkostningsbudgetter efter `concurrency_group` |
| `QUEUETY_RESOURCE_TIME_HEADROOM_MS` | Reserveret tidsmargin for worker-kørsler, der kun kører én gang |

## Worker-livscyklus

En worker stopper på kontrolleret vis efter at have afsluttet sit aktuelle job, når en af følgende betingelser er opfyldt:

| Betingelse | Konfiguration |
|---|---|
| Maksimalt antal behandlede jobs | `QUEUETY_WORKER_MAX_JOBS` (standard: 1000) |
| Maksimal hukommelse overskredet | `QUEUETY_WORKER_MAX_MEMORY` (standard: 128 MB) |

Efter stoppet afsluttes workeren korrekt. I produktion genstarter en procesmanager den automatisk.

Signaler håndteres endnu ikke på kontrolleret vis ([#4](https://github.com/inline0/queuety/issues/4)). En enkelt `wp queuety work`-proces installerer ingen signalhandler, så `SIGTERM` eller `SIGINT` (Ctrl+C) afslutter den øjeblikkeligt, også midt i et job. Jobbet forbliver `processing`, indtil gendannelse af forældede jobs nulstiller det efter `QUEUETY_STALE_TIMEOUT` sekunder, så sørg for, at handlers tåler genkørsel. En worker-pool videresender `SIGTERM` til sine underprocesser, men underprocesserne reagerer ikke på det, så poolen fortsætter, indtil de stopper af en af ovenstående årsager. Når en pool skal stoppes, skal procesmanageren have en stop-timeout, hvorefter den sender `SIGKILL`.

## Samtidighed med flere workers

Flaget `--workers=N` opretter N underprocesser med `pcntl_fork()`. Hvert barn opretter sin egen databaseforbindelse og behandler jobs uafhængigt. Forældreprocessen overvåger børnene og genstarter dem, der går ned.

```bash
wp queuety work --queue=default --workers=4
```

Krav:
Udvidelserne `pcntl` og `posix` PHP skal være installeret (uden `pcntl` fejler kommandoen med "pcntl extension is required for --workers=N."), og hvert barn bruger sin egen databaseforbindelse, så din indstilling for MySQL `max_connections` skal kunne håndtere puljen. Adaptive puljer (`--min-workers`/`--max-workers`) har de samme krav.

## Adaptive arbejderpuljer

Adaptive puljer holder et minimum antal arbejdere klar og skalerer derefter op og ned inden for et konfigureret interval:

```bash
wp queuety work --queue=providers --min-workers=2 --max-workers=6
```

Forældreprocessen overvåger den købare efterslæb i det valgte køsæt og justerer antallet af børn efter efterslæbet, begrænset af det konfigurerede maksimum. Når der bliver stille i køen, venter puljen i den konfigurerede inaktivitetsperiode, før den skalerer ned, så korte spidsbelastninger ikke straks får proceslisten til at ændre sig.

Op skaleringen er stadig forsigtig. Når Queuety kan læse hukommelsesdata fra containeren eller værten, nægter den at tilføje flere børn, hvis der ikke er nok ledig hukommelse til endnu en fuld arbejderressource.

Skaleringsløkken på forældresiden styres med:

| Konstant | Beskrivelse |
|---|---|
| `QUEUETY_WORKER_POOL_SCALE_INTERVAL` | Hvor ofte forælderen tilpasser puljens størrelse |
| `QUEUETY_WORKER_POOL_IDLE_GRACE` | Hvor længe efterslæbet skal være væk, før der skaleres ned |

## Gendannelse af forældede jobs

Hvis en arbejder går ned, mens den behandler et job, efterlades jobbet med status `processing`. En langkørende arbejder kontrollerer cirka én gang i minuttet, om jobs har været i `processing` længere end `QUEUETY_STALE_TIMEOUT` sekunder. Et forældet job med forsøg tilbage prøves igen efter sin ventetid; et job, der har brugt alle sine forsøg, begraves, og dets workflow markeres som mislykket. `--once` arbejdere og WP-Cron-fallbacken udfører ikke denne kontrol.

Gendan forældede jobs manuelt:

```bash
wp queuety recover
```

## Tømningstilstand

Behandl alle ventende jobs, og afslut derefter. Nyttigt til test eller engangs-batchbehandling:

```bash
wp queuety flush
wp queuety flush --queue=emails
```

## Produktionsudrulning

I produktion skal du bruge en procesmanager til at holde arbejdere kørende. Her er to almindelige metoder.

### Supervisord

```ini
[program:queuety-default]
command=wp queuety work --queue=default
directory=/var/www/html
autostart=true
autorestart=true
numprocs=2
process_name=%(program_name)s_%(process_num)02d
stdout_logfile=/var/log/queuety-default.log
stderr_logfile=/var/log/queuety-default-error.log

[program:queuety-emails]
command=wp queuety work --queue=emails
directory=/var/www/html
autostart=true
autorestart=true
numprocs=1
stdout_logfile=/var/log/queuety-emails.log
stderr_logfile=/var/log/queuety-emails-error.log
```

### Systemd

```ini
[Unit]
Description=Queuety Worker (default queue)
After=mysql.service

[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/html
ExecStart=/usr/local/bin/wp queuety work --queue=default
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
```

Aktivér og start:

```bash
sudo systemctl enable queuety-worker
sudo systemctl start queuety-worker
```

### Tips til udrulning

Kør separate arbejdere for separate køer, når du har brug for stærkere isolering. Brug `--workers=N`, når arbejdsbelastningen er CPU-bundet, og foretræk individuelt overvågede arbejdere, når arbejdsbelastningen primært er I/O. Angiv `QUEUETY_WORKER_MAX_JOBS`, hvis du ønsker periodiske genstarter for at frigøre hukommelse, og hold øje med antallet af `buried` via [webhooks](https://queuety.inline0.dev/da/docs/features/webhooks) eller [målinger](https://queuety.inline0.dev/da/docs/features/metrics).
