
# Delavci

Delavci so dolgotrajno delujoči procesi, ki preverjajo zbirko podatkov za čakajoča opravila, jih izvedejo in napredujejo delovne tokove. Ukaz `wp queuety work` se izvaja znotraj WP-CLI, medtem ko se sama čakalna vrsta prevzame neposredno iz MySQL prek najboljšega razpoložljivega gonilnika DB Queuety.

Vtičnik namesti tudi privzeti WordPress cron, ki se zažene enkrat na minuto kot nadomestna možnost v okoljih brez dostopa do lupine. Ta stran obravnava namenske delavce WP-CLI, ki so priporočeni način namestitve za večjo prepustnost.

## Zagon delavca

```bash
wp queuety work
```

S tem zaženete enega delavca v čakalni vrsti `default`. Deluje v zanki: prevzame opravilo, ga izvede in ponovi. Ko je čakalna vrsta prazna, pred ponovnim preverjanjem počaka `QUEUETY_WORKER_SLEEP` sekund (privzeto: 1).

### Možnosti

| Možnost | Opis |
|---|---|
| `--queue=<queue>` | Queue(s) za obdelavo; za razvrščanje po prednosti jih ločite z vejicami (privzeto: `default`) |
| `--once` | Obdela največ eno opravilo in konča |
| `--workers=<n>` | Razveji N delavskih procesov (zahteva razširitvi `pcntl` in `posix`) |
| `--min-workers=<n>` | Najmanjše število delavcev za prilagodljiv sklad. Zahteva `--max-workers` |
| `--max-workers=<n>` | Največje število delavcev za prilagodljiv sklad |

```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
```

## Prednostne naloge več čakalnih vrst

En delavec lahko obdeluje več čakalnih vrst po vrstnem redu prednosti. Ukazu `--queue` podajte z vejicami ločen seznam imen čakalnih vrst:

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

Delavec poskuša prevzeti opravilo iz vsake čakalne vrste v navedenem vrstnem redu. Najprej preveri `critical`. Če ima `critical` opravilo, ga obdela. Če je `critical` prazna, nadaljuje z `default`, nato pa z `low`. To pomeni, da se čakalne vrste z višjo prednostjo vedno izpraznijo pred tistimi z nižjo.

### Kako deluje razvrščanje po prednosti

Pri vsaki ponovitvi delavec poskuša prevzeti opravilo iz prve čakalne vrste na seznamu. Če je ta prazna ali začasno ustavljena, nadaljuje z naslednjo in tako naprej, dokler ne najde opravila ali izčrpa seznama. Če ne najde opravila nikjer, počaka in poskusi znova. To je strog model prednosti, kar pomeni, da stalen tok opravil `critical` izstrada čakalni vrsti `default` in `low`. Če čakalne vrste z nižjo prednostjo potrebujejo zagotovljeno prepustnost, uporabite namenske delavce.

### Uporaba več čakalnih vrst v PHP

Metodi `Worker::run()` in `Worker::flush()` sprejemata niz ali polje:

```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' );
```

### Strategije namestitve

**Namenski delavci za vsako čakalno vrsto** vam omogočajo popoln nadzor nad sočasnostjo in izolacijo. Vsaka čakalna vrsta dobi svoj delavski process(es) in je ni mogoče izstradati zaradi drugih čakalnih vrst:

```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
```

**Razvrščanje po prednosti z enim delavcem** je enostavnejše za upravljanje in dobro deluje, kadar lahko čakalne vrste z nižjo prednostjo prenesejo zamude:

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

Oba pristopa lahko tudi združite: za zagotovljeno prepustnost uporabite namenske delavce za `critical`, za vse drugo pa delavca, ki razvršča po prednosti:

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

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

## Dodeljevanje virov glede na njihovo razpoložljivost

Delavci ne prevzamejo zgolj naslednje čakajoče vrstice. Pred začetkom prevzetega opravila lahko Queuety uporabi groba preverjanja za sprejem na podlagi skupine sočasnosti opravila in nedavnega profila izvajanja za ta obravnavalnik.

Za širši model in razlago povezave z metapodatki opravil ter proračuni delovnih tokov glejte [Upravljanje virov](https://queuety.inline0.dev/sl/docs/features/resource-management).

Skupina sočasnosti več obravnavalnikom ali razredom opravil določi skupno omejitev. Če več ponudnikov, ki zahtevajo veliko virov, označite z isto skupino in omejitvijo, bo delavec sprostil na novo prevzeto delo, namesto da bi ga začel, ko je skupina zasičena. Tako neodvisne čakalne vrste ne preobremenijo istega nadaljnjega sistema zgolj zato, ker je na voljo več nedejavnih delavcev.

Nedavni dnevniki izvajanj prispevajo tudi k preprostemu profilu za sprejem. Ko je omogočeno upravljanje virov, Queuety preveri nedavno povprečno trajanje in največjo porabo pomnilnika za obravnavalnik, ki ga bo zagnal. Če se trenutni delavec že približuje nastavljeni omejitvi pomnilnika, je čakalna vrsta ali skupina ponudnikov že dosegla uteženi proračun, kaže, da trenutni vsebnik nima dovolj prostega pomnilnika za opaženi profil obravnavalnika, ali se izvajanje v slogu `--once` približuje svoji časovni omejitvi, Queuety opravilo odloži, namesto da bi začel delo, ki se verjetno ne bo pravilno končalo.

Pravilnik vključite v definiciji dela, ne z ukazom delavca:

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

Iste metapodatke lahko pripnete razredom opravil, ki jih je mogoče odpreti, z javnimi lastnostmi ali posameznemu odpremu prek `PendingJob::concurrency_group()` in `PendingJob::cost_units()`.

Profil za sprejem na strani delavca nadzorujejo te konstante:

| Konstanta | Opis |
|---|---|
| `QUEUETY_RESOURCE_ADMISSION` | Omogoči ali onemogoči preverjanja za sprejem na podlagi profila |
| `QUEUETY_RESOURCE_PROFILE_WINDOW_MINUTES` | Kako daleč v preteklost sežejo podatki za nedavne profile obravnavalnikov |
| `QUEUETY_RESOURCE_PROFILE_TTL` | Čas veljavnosti predpomnilnika za nedavne profile obravnavalnikov |
| `QUEUETY_RESOURCE_MEMORY_HEADROOM_MB` | Rezervna pomnilniška zmogljivost pred sprejemom novega opravila |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS` | Omogoči ali onemogoči najboljša približna preverjanja pomnilnika vsebnika ali gostitelja |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_HEADROOM_MB` | Rezervna sistemska pomnilniška zmogljivost pred sprejemom novega opravila |
| `QUEUETY_RESOURCE_QUEUE_COST_BUDGETS` | Uteženi proračuni stroškov po imenu čakalne vrste |
| `QUEUETY_RESOURCE_GROUP_COST_BUDGETS` | Uteženi proračuni stroškov po `concurrency_group` |
| `QUEUETY_RESOURCE_TIME_HEADROOM_MS` | Rezervna časovna zmogljivost za enkratna izvajanja delavcev |

## Življenjski cikel delavca

Delavec se po končanem trenutnem opravilu ustavi postopoma, ko je izpolnjen kateri koli od teh pogojev:

| Pogoj | Konfiguracija |
|---|---|
| Največje število obdelanih opravil | `QUEUETY_WORKER_MAX_JOBS` (privzeto: 1000) |
| Prekoračena največja poraba pomnilnika | `QUEUETY_WORKER_MAX_MEMORY` (privzeto: 128 MB) |

Po zaustavitvi delavec pravilno konča. V produkciji ga upravitelj procesov samodejno znova zažene.

Signali še niso obravnavani na varen način ([#4](https://github.com/inline0/queuety/issues/4)). Posamezen proces `wp queuety work` ne namesti obravnavalnika signalov, zato ga `SIGTERM` ali `SIGINT` (Ctrl+C) takoj konča, tudi sredi opravila. Opravilo ostane v stanju `processing`, dokler ga obnovitev zastarelih opravil po `QUEUETY_STALE_TIMEOUT` sekundah ne ponastavi, zato poskrbite, da je mogoče obravnavalnike varno znova zagnati. Sklad delavcev posreduje `SIGTERM` svojim podrejenim procesom, vendar se ti nanj ne odzovejo, zato sklad deluje naprej, dokler se ne ustavijo iz enega od zgornjih razlogov. Ko morate ustaviti sklad, nastavite časovno omejitev zaustavitve v upravitelju procesov, po kateri ta pošlje `SIGKILL`.

## Sočasnost več delavcev

Zastavica `--workers=N` razveji N podrejenih procesov z uporabo `pcntl_fork()`. Vsak podrejeni proces ustvari lastno povezavo z zbirko podatkov in neodvisno obdeluje opravila. Nadrejeni proces spremlja podrejene procese in znova zažene vse, ki se zrušijo.

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

Zahteve:
Razširitvi `pcntl` in `posix` PHP morata biti nameščeni (brez `pcntl` ukaz odpove z napako »pcntl extension is required for --workers=N.«), vsak podrejeni proces pa uporablja svojo povezavo z zbirko podatkov, zato mora vaša nastavitev MySQL `max_connections` podpirati celoten sklad. Prilagodljivi skladi (`--min-workers`/`--max-workers`) imajo enake zahteve.

## Prilagodljivi skladi delavcev

Prilagodljivi skladi ohranjajo najmanjše število pripravljenih delavcev, nato pa se povečujejo in zmanjšujejo znotraj nastavljenega razpona:

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

Nadrejeni proces spremlja število opravil, ki jih je mogoče prevzeti, v izbranem naboru čakalnih vrst ter prilagaja število podrejenih procesov glede na to število, do nastavljene največje vrednosti. Ko se čakalna vrsta umiri, sklad počaka, da poteče obdobje mirovanja, nato pa zmanjša število procesov, da kratki sunki obremenitve ne povzročijo takojšnjega nenehnega spreminjanja seznama procesov.

Povečanje obsega je še vedno previdno. Ko lahko Queuety prebere telemetrijo pomnilnika vsebnika ali gostitelja, ne doda novih podrejenih procesov, če ni dovolj prostega pomnilnika za celotno zmogljivost dodatnega delavca.

Zanka za prilagajanje obsega na strani nadrejenega procesa je nadzorovana z:

| Konstanta | Opis |
|---|---|
| `QUEUETY_WORKER_POOL_SCALE_INTERVAL` | Kako pogosto nadrejeni proces uskladi velikost sklada |
| `QUEUETY_WORKER_POOL_IDLE_GRACE` | Kako dolgo mora trajati mirovanje čakalne vrste, preden se obseg zmanjša |

## Obnovitev zastarelih opravil

Če se delavec med obdelavo opravila zruši, opravilo ostane v stanju `processing`. Dolgotrajno delujoči delavec približno enkrat na minuto preveri, ali so opravila v stanju `processing` dlje kot `QUEUETY_STALE_TIMEOUT` sekund. Zastarelo opravilo, ki ima še poskuse na voljo, se znova izvede po zakasnitvi, določeni za ponovni poskus; opravilo, pri katerem so bili porabljeni vsi poskusi, se skrije, njegov delovni tok pa je označen kot neuspešen. Delavci `--once` in nadomestna možnost WP-Cron tega preverjanja ne izvajajo.

Zastarela opravila obnovite ročno:

```bash
wp queuety recover
```

## Način izpraznitve

Obdelajte vsa čakajoča opravila in končajte. Primerno za testiranje ali enkratno paketno obdelavo:

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

## Namestitev v produkcijo

V produkciji uporabite upravitelja procesov, da bodo delavci stalno delovali. Tu sta dva pogosta pristopa.

### 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
```

Omogočite in zaženite:

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

### Nasveti za namestitev

Za boljšo izolacijo za posamezne čakalne vrste zaženite ločene delavce. Če je obremenitev vezana na procesor, uporabite `--workers=N`, za obremenitve, ki so večinoma vezane na V/I, pa raje uporabite ločeno nadzorovane delavce. Nastavite `QUEUETY_WORKER_MAX_JOBS`, če želite občasne ponovne zagone za sprostitev pomnilnika, in spremljajte število `buried` prek [spletnih kavljev](https://queuety.inline0.dev/sl/docs/features/webhooks) ali [metrik](https://queuety.inline0.dev/sl/docs/features/metrics).
