
# Työntekijät

Työntekijät ovat pitkäkestoisia prosesseja, jotka etsivät tietokannasta odottavia töitä, suorittavat ne ja vievät työnkulkuja eteenpäin. `wp queuety work`-komento suoritetaan WP-CLI-ympäristössä, ja jono otetaan suoraan käyttöön MySQL-ratkaisun kautta käyttäen parasta saatavilla olevaa Queuety-tietokanta-ajuria.

Lisäosa asentaa myös oletusarvoisen kerran minuutissa suoritettavan WordPress cron-vararatkaisun ympäristöihin, joissa komentorivikäyttö ei ole mahdollista. Tämä sivu käsittelee erillisiä WP-CLI-työntekijöitä, jotka ovat suositeltu vaihtoehto suurempaa suorituskykyä vaativaan käyttöönottoon.

## Työntekijän käynnistäminen

```bash
wp queuety work
```

Tämä käynnistää yhden työntekijän jonossa `default`. Työntekijä toimii silmukassa: ottaa työn, suorittaa sen ja toistaa. Kun jono on tyhjä, työntekijä nukkuu `QUEUETY_WORKER_SLEEP` sekuntia (oletus: 1) ennen seuraavaa kyselyä.

### Asetukset

| Valinta | Kuvaus |
|---|---|
| `--queue=<queue>` | Käsiteltävät Queue(s), pilkuilla eroteltuna tärkeysjärjestykseen (oletus: `default`) |
| `--once` | Käsittele enintään yksi työ ja poistu |
| `--workers=<n>` | Käynnistä N työntekijäprosessia (edellyttää laajennuksia `pcntl` ja `posix`) |
| `--min-workers=<n>` | Mukautuvan poolin työntekijöiden vähimmäismäärä. Edellyttää `--max-workers` |
| `--max-workers=<n>` | Mukautuvan poolin työntekijöiden enimmäismäärä |

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

## Usean jonon tärkeysjärjestys

Yksi työntekijä voi käsitellä useita jonoja tärkeysjärjestyksessä. Välitä pilkuilla eroteltu jononimien luettelo kohteelle `--queue`:

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

Työntekijä yrittää ottaa työn kustakin jonosta luetellussa järjestyksessä. Se tarkistaa ensin jonon `critical`. Jos jonossa `critical` on työ, se käsittelee kyseisen työn. Jos jono `critical` on tyhjä, se siirtyy jonoon `default` ja sitten jonoon `low`. Näin korkeamman tärkeysasteen jonot tyhjennetään aina ennen alemman tärkeysasteen jonoja.

### Miten tärkeysjärjestys toimii

Jokaisella kierroksella työntekijä yrittää ottaa työn luettelon ensimmäisestä jonosta. Jos jono on tyhjä tai keskeytetty, se siirtyy seuraavaan jonoon ja jatkaa, kunnes löytää työn tai käy luettelon läpi. Jos töitä ei löydy mistään, työntekijä nukkuu ja yrittää uudelleen. Tämä on tiukka tärkeysjärjestysmalli: jatkuva `critical`-töiden virta voi näännyttää jonot `default` ja `low`. Jos alemman tärkeysasteen jonoille tarvitaan taattu suorituskapasiteetti, käytä erillisiä työntekijöitä.

### Usean jonon käyttö kohteessa PHP

Metodit `Worker::run()` ja `Worker::flush()` hyväksyvät merkkijonon tai taulukon:

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

### Käyttöönoton strategiat

**Omat työntekijät kullekin jonolle** antavat täyden hallinnan samanaikaisuuteen ja eristykseen. Kukin jono saa oman työntekijän process(es), eivätkä muut jonot voi näännyttää sitä:

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

**Tärkeysjärjestys yhdellä työntekijällä** on helpompi hallita ja toimii hyvin, kun alemman tärkeysasteen jonot kestävät viiveitä:

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

Voit myös yhdistää molemmat tavat: käytä omia työntekijöitä jonolle `critical` suorituskapasiteetin takaamiseksi ja tärkeysjärjestykseen perustuvaa työntekijää kaikkeen muuhun:

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

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

## Resurssit huomioiva hyväksyntä

Työntekijät tekevät muutakin kuin varaavat seuraavan odottavan rivin. Ennen varatun työn aloittamista Queuety voi tehdä karkeita pääsytarkistuksia työn samanaikaisuusryhmän ja kyseisen käsittelijän viimeaikaisen suoritusprofiilin perusteella.

Laajempi malli sekä sen yhteys työn metatietoihin ja työnkulkujen budjetteihin kuvataan kohdassa [Resurssien hallinta](https://queuety.inline0.dev/fi/docs/features/resource-management).

Samanaikaisuusryhmä asettaa useille käsittelijöille tai työluokille yhteisen ylärajan. Jos merkitset useita paljon resursseja käyttäviä palveluntarjoajia samalla ryhmällä ja rajalla, työntekijä vapauttaa juuri varaamansa työn sen sijaan, että aloittaisi sen, kun ryhmä on täynnä. Näin erilliset jonot eivät ryntää samaan jatkojärjestelmään vain siksi, että useita työntekijöitä on vapaana.

Viimeaikaiset suorituslokit muodostavat myös yksinkertaisen pääsyprofiilin. Kun resurssipohjainen pääsynhallinta on käytössä, Queuety tarkastelee sen käsittelijän viimeaikaista keskimääräistä suoritusaikaa ja huippumuistinkulutusta, jonka se aikoo käynnistää. Jos nykyinen työntekijä on jo lähellä määritettyä muistirajaansa, jono tai palveluntarjoajaryhmä on jo painotetun budjettinsa rajoilla, nykyisessä säilössä ei näytä olevan riittävästi vapaata muistia käsittelijän havaitun profiilin tarpeisiin tai `--once`-tyylisen ajon aikaikkuna on lähellä loppuaan, Queuety siirtää työn myöhemmäksi sen sijaan, että käynnistäisi työn, joka ei todennäköisesti valmistu ongelmitta.

Otat käytännön käyttöön työn määrittelyssä, et työntekijäkomennossa:

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

Samat metatiedot voi liittää julkisia ominaisuuksia sisältäviin suoritettaviin työluokkiin tai yksittäiseen suoritukseen käyttämällä `PendingJob::concurrency_group()` ja `PendingJob::cost_units()`.

Työntekijän puolen pääsyprofiilia ohjataan näillä vakioilla:

| Vakio | Kuvaus |
|---|---|
| `QUEUETY_RESOURCE_ADMISSION` | Ota profiilipohjaiset pääsytarkistukset käyttöön tai poista ne käytöstä |
| `QUEUETY_RESOURCE_PROFILE_WINDOW_MINUTES` | Kuinka pitkältä ajalta viimeaikaiset käsittelijäprofiilit muodostetaan |
| `QUEUETY_RESOURCE_PROFILE_TTL` | Viimeaikaisten käsittelijäprofiilien välimuistin TTL |
| `QUEUETY_RESOURCE_MEMORY_HEADROOM_MB` | Varattu muistivara ennen uuden työn sallimista |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS` | Ota käyttöön tai poista käytöstä parhaansa mukaan tehtävät säilön tai isäntäkoneen muistintarkistukset |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_HEADROOM_MB` | Varattu järjestelmämuistin määrä ennen uuden työn sallimista |
| `QUEUETY_RESOURCE_QUEUE_COST_BUDGETS` | Jonon nimen mukaan määritetyt painotetut kustannusbudjetit |
| `QUEUETY_RESOURCE_GROUP_COST_BUDGETS` | Kohteen `concurrency_group` mukaan määritetyt painotetut kustannusbudjetit |
| `QUEUETY_RESOURCE_TIME_HEADROOM_MS` | Kertaluonteisten työntekijäajojen varattu aikavara |

## Työntekijän elinkaari

Työntekijä pysähtyy hallitusti suoritettuaan nykyisen työn, kun jokin seuraavista ehdoista täyttyy:

| Ehto | Määritys |
|---|---|
| Käsiteltyjen töiden enimmäismäärä | `QUEUETY_WORKER_MAX_JOBS` (oletus: 1000) |
| Muistinkulutus ylittää rajan | `QUEUETY_WORKER_MAX_MEMORY` (oletus: 128 MB) |

Pysähtymisen jälkeen työntekijä sulkeutuu siististi. Tuotantoympäristössä prosessienhallintaohjelma käynnistää sen automaattisesti uudelleen.

Signaaleja ei vielä käsitellä hallitusti ([#4](https://github.com/inline0/queuety/issues/4)). Yksittäinen `wp queuety work`-prosessi ei asenna signaalinkäsittelijää, joten `SIGTERM` tai `SIGINT` (Ctrl+C) päättää sen välittömästi myös kesken työn. Työ jää tilaan `processing`, kunnes vanhojen töiden palautus nollaa sen `QUEUETY_STALE_TIMEOUT` sekunnin kuluttua, joten varmista, että käsittelijät voi suorittaa turvallisesti uudelleen. Työntekijäpooli välittää signaalin `SIGTERM` lapsiprosesseilleen, mutta ne eivät reagoi siihen, joten pooli jatkaa toimintaansa, kunnes prosessit pysähtyvät jostakin edellä mainitusta syystä. Kun haluat pysäyttää poolin, määritä prosessienhallintaohjelmalle pysäytyksen aikakatkaisu, jonka jälkeen se lähettää signaalin `SIGKILL`.

## Usean työntekijän rinnakkaisuus

`--workers=N`-lippu käynnistää N lapsiprosessia käyttämällä `pcntl_fork()`. Kukin lapsiprosessi luo oman tietokantayhteyden ja käsittelee töitä itsenäisesti. Pääprosessi valvoo lapsiprosesseja ja käynnistää uudelleen kaatuneet prosessit.

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

Vaatimukset:
`pcntl`- ja `posix`-laajennusten PHP on oltava asennettuina (ilman `pcntl`-laajennusta komento epäonnistuu virheellä "pcntl extension is required for --workers=N."), ja kukin lapsiprosessi käyttää omaa tietokantayhteyttä, joten MySQL-asetuksen `max_connections` on riitettävä koko poolille. Mukautuvia pooleja (`--min-workers`/`--max-workers`) koskevat samat vaatimukset.

## Mukautuvat työntekijäpoolit

Mukautuvat poolit pitävät vähimmäismäärän työntekijöitä valmiina ja kasvavat tai pienenevät sitten määritetyn vaihteluvälin sisällä:

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

Pääprosessi tarkkailee valitun jonojoukon varattavissa olevaa työjonoa ja säätää lapsiprosessien määrää sen mukaisesti määritettyyn enimmäismäärään asti. Kun jono hiljenee, pooli odottaa joutokäyntiin varatun ajan ennen koon pienentämistä, jotta lyhyet työpiikit eivät aiheuta prosessiluettelon jatkuvaa vaihtelua.

Skaalaus ylöspäin on edelleen varovaista. Kun Queuety pystyy lukemaan säilön tai isäntäkoneen muistitietoja, se ei lisää lapsiprosesseja, jos yhden kokonaisen työntekijän tarpeisiin ei ole riittävästi vapaata muistia.

Pääprosessin skaalaussilmukkaa ohjataan seuraavilla asetuksilla:

| Vakio | Kuvaus |
|---|---|
| `QUEUETY_WORKER_POOL_SCALE_INTERVAL` | Kuinka usein pääprosessi sovittaa poolin kokoa |
| `QUEUETY_WORKER_POOL_IDLE_GRACE` | Kuinka kauan työjonon on pysyttävä hiljaisena ennen koon pienentämistä |

## Vanhentuneiden töiden palautus

Jos työntekijä kaatuu työn käsittelyn aikana, työ jää tilaan `processing`. Pitkään käynnissä oleva työntekijä tarkistaa noin kerran minuutissa, onko jokin työ ollut tilassa `processing` yli `QUEUETY_STALE_TIMEOUT` sekuntia. Vanhentunut työ, jolla on yrityksiä jäljellä, yritetään uudelleen viiveajan jälkeen; kaikki yrityksensä käyttänyt työ siirretään sivuun ja sen työnkulku merkitään epäonnistuneeksi. `--once`-työntekijät ja WP-Cron-varajärjestelmä eivät suorita tätä tarkistusta.

Palauta vanhentuneet työt manuaalisesti:

```bash
wp queuety recover
```

## Tyhjennystila

Käsittele kaikki odottavat työt ja lopeta. Sopii testaukseen tai kertaluonteiseen eräkäsittelyyn:

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

## Tuotantoon vienti

Pidä työntekijät käynnissä tuotantoympäristössä prosessienhallintaohjelman avulla. Tässä on kaksi yleistä vaihtoehtoa.

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

Ota käyttöön ja käynnistä:

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

### Käyttöönoton vinkkejä

Käynnistä erilliset työntekijät eri jonoille, kun tarvitset vahvempaa eristystä. Käytä `--workers=N`-asetusta, kun työkuorma rajoittuu suorittimeen, ja suosi erikseen valvottuja työntekijöitä, kun työkuorma koostuu pääosin I/O-toiminnoista. Määritä `QUEUETY_WORKER_MAX_JOBS`, jos haluat vapauttaa muistia säännöllisillä uudelleenkäynnistyksillä, ja seuraa `buried`-määrää [webhookien](https://queuety.inline0.dev/fi/docs/features/webhooks) tai [mittareiden](https://queuety.inline0.dev/fi/docs/features/metrics) kautta.
