
# Darbininkai

Darbininkai yra ilgai veikiantys procesai, kurie duomenų bazėje ieško laukiančių užduočių, jas vykdo ir perkelia darbo sekas į priekį. Komanda `wp queuety work` vykdoma WP-CLI aplinkoje, o pati eilė tiesiogiai užklausiama iš MySQL naudojant geriausią prieinamą Queuety DB tvarkyklę.

Papildinys taip pat įdiegia numatytąją kartą per minutę vykdomą WordPress cron atsarginę priemonę aplinkoms, kuriose nėra prieigos prie apvalkalo. Šiame puslapyje aptariami atskiri WP-CLI darbininkai – rekomenduojamas didesnio pralaidumo diegimo būdas.

## Darbininko paleidimas

```bash
wp queuety work
```

Taip paleidžiamas vienas `default` eilės darbininkas. Jis veikia ciklu: paima užduotį, ją įvykdo ir kartoja. Kai eilė tuščia, prieš kitą užklausą jis laukia `QUEUETY_WORKER_SLEEP` sekundę (numatytoji reikšmė: 1).

### Parinktys

| Parinktis | Aprašymas |
|---|---|
| `--queue=<queue>` | Queue(s), kurias reikia apdoroti; kableliais atskirtas sąrašas nustato prioritetų tvarką (numatytoji reikšmė: `default`) |
| `--once` | Apdoroja ne daugiau kaip vieną užduotį ir baigia darbą |
| `--workers=<n>` | Paleidžia N darbininkų procesų (reikalingi plėtiniai `pcntl` ir `posix`) |
| `--min-workers=<n>` | Minimalus adaptyvaus telkinio darbininkų skaičius. Reikalingas `--max-workers` |
| `--max-workers=<n>` | Maksimalus adaptyvaus telkinio darbininkų skaičius |

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

## Kelių eilių prioritetai

Vienas darbininkas gali apdoroti kelias eiles pagal prioritetų tvarką. Perduokite kableliais atskirtą eilių pavadinimų sąrašą parametrui `--queue`:

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

Darbininkas bando paimti užduotį iš kiekvienos eilės nurodyta tvarka. Pirmiausia tikrinama `critical`. Jei `critical` yra užduotis, darbininkas ją apdoroja. Jei `critical` tuščia, jis pereina prie `default`, tada prie `low`. Taigi aukštesnio prioriteto eilės visada ištuštinamos prieš žemesnio prioriteto eiles.

### Kaip veikia prioritetų tvarka

Kiekvienoje iteracijoje darbininkas bando paimti užduotį iš pirmos sąrašo eilės. Jei ji tuščia arba pristabdyta, pereinama prie kitos eilės; taip tęsiama, kol randama užduotis arba patikrinamas visas sąrašas. Jei užduoties niekur nerandama, darbininkas palaukia ir bando dar kartą. Taikomas griežtas prioritetų modelis: nuolatinis `critical` užduočių srautas neleis apdoroti `default` ir `low` užduočių. Jei reikia užtikrinti žemesnio prioriteto eilių pralaidumą, naudokite atskirus darbininkus.

### Kelių eilių naudojimas su PHP

Metodams `Worker::run()` ir `Worker::flush()` galima perduoti eilutę arba masyvą:

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

### Diegimo strategijos

**Atskiri kiekvienos eilės darbininkai** suteikia visišką lygiagretumo ir izoliavimo kontrolę. Kiekviena eilė turi savo darbininkų process(es), todėl kitų eilių užduotys negali jos užgožti:

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

**Vienas darbininkas su prioritetų tvarka** yra paprasčiau valdomas ir tinka, kai žemesnio prioriteto eilės gali palaukti:

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

Galite derinti abu būdus: naudoti atskirus darbininkus `critical`, kad būtų užtikrintas pralaidumas, ir vieną pagal prioritetus veikiančią darbo užduotį visoms kitoms eilėms:

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

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

## Išteklius įvertinantis priėmimas

Darbininkai ne tik paima kitą laukiančią eilutę. Prieš pradedant vykdyti paimtą užduotį, Queuety gali atlikti apytiksles priėmimo patikras pagal užduoties lygiagretumo grupę ir naujausią tos apdorojimo funkcijos vykdymo profilį.

Išsamesnį modelį ir paaiškinimą, kaip jis siejasi su užduočių metaduomenimis bei darbo sekų biudžetais, rasite [Išteklių valdymas](https://queuety.inline0.dev/lt/docs/features/resource-management).

Lygiagretumo grupė leidžia kelioms apdorojimo funkcijoms arba užduočių klasėms taikyti bendrą limitą. Jei keliems daug išteklių naudojantiems tiekėjams priskirsite tą pačią grupę ir limitą, prisotinus grupę darbininkas atlaisvins ką tik paimtą užduotį, užuot ją pradėjęs vykdyti. Taip nepriklausomos eilės neužverčia vienos paskesnės sistemos užklausomis vien todėl, kad yra keli laisvi darbininkai.

Naujausi vykdymo žurnalai taip pat naudojami paprastam priėmimo profiliui sudaryti. Įjungus išteklių vertinimą, Queuety tikrina neseną vidutinę trukmę ir didžiausią atminties naudojimą tos apdorojimo funkcijos, kurią ketinama vykdyti. Jei dabartinis darbininkas jau beveik pasiekė nustatytą atminties limitą, eilė ar tiekėjų grupė jau išnaudojo savo svertinį biudžetą, dabartiniame konteineryje, regis, nepakanka laisvos atminties šios funkcijos stebėtam profiliui arba `--once` tipo vykdymas artėja prie laiko limito, Queuety atideda užduotį, užuot pradėjęs darbą, kurio tikriausiai nepavyks tinkamai užbaigti.

Šią strategiją įjungsite darbo apibrėžtyje, o ne darbininko komandoje:

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

Tuos pačius metaduomenis galima pridėti prie išsiunčiamų užduočių klasių naudojant viešąsias savybes arba prie atskiro išsiuntimo per `PendingJob::concurrency_group()` ir `PendingJob::cost_units()`.

Darbininko priėmimo profilį valdo šios konstantos:

| Konstanta | Aprašymas |
|---|---|
| `QUEUETY_RESOURCE_ADMISSION` | Įjungti arba išjungti profiliu pagrįstas priėmimo patikras |
| `QUEUETY_RESOURCE_PROFILE_WINDOW_MINUTES` | Kiek laiko atgal žiūrėti sudarant naujausius apdorojimo funkcijų profilius |
| `QUEUETY_RESOURCE_PROFILE_TTL` | Naujausių apdorojimo funkcijų profilių talpyklos galiojimo laikas |
| `QUEUETY_RESOURCE_MEMORY_HEADROOM_MB` | Rezervuotas atminties rezervas prieš priimant kitą užduotį |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS` | Įjungti arba išjungti apytiksles konteinerio arba pagrindinio kompiuterio atminties patikras |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_HEADROOM_MB` | Rezervuotas sistemos atminties rezervas prieš priimant kitą užduotį |
| `QUEUETY_RESOURCE_QUEUE_COST_BUDGETS` | Svertiniai sąnaudų biudžetai pagal eilės pavadinimą |
| `QUEUETY_RESOURCE_GROUP_COST_BUDGETS` | Svertiniai sąnaudų biudžetai pagal `concurrency_group` |
| `QUEUETY_RESOURCE_TIME_HEADROOM_MS` | Rezervuotas laiko rezervas vienkartiniam darbininko vykdymui |

## Darbininko gyvavimo ciklas

Darbininkas baigia darbą tvarkingai, užbaigęs dabartinę užduotį, jei įvykdoma kuri nors iš šių sąlygų:

| Sąlyga | Konfigūracija |
|---|---|
| Apdorota daugiausia užduočių | `QUEUETY_WORKER_MAX_JOBS` (numatytoji reikšmė: 1000) |
| Viršytas didžiausias atminties kiekis | `QUEUETY_WORKER_MAX_MEMORY` (numatytoji reikšmė: 128 MB) |

Sustojęs darbininkas tvarkingai užbaigia darbą. Produkcinėje aplinkoje procesų tvarkyklė jį automatiškai paleidžia iš naujo.

Signalai kol kas nėra tvarkomi tinkamai ([#4](https://github.com/inline0/queuety/issues/4)). Atskiras `wp queuety work` procesas neįdiegia signalų apdorojimo funkcijos, todėl `SIGTERM` arba `SIGINT` (Ctrl+C) iš karto jį nutraukia, net jei vykdoma užduotis dar nebaigta. Ta užduotis lieka būsenoje `processing`, kol pasenusių užduočių atkūrimas ją iš naujo nustato po `QUEUETY_STALE_TIMEOUT` sekundžių, todėl pasirūpinkite, kad apdorojimo funkcijas būtų saugu vykdyti pakartotinai. Darbininkų telkinys persiunčia `SIGTERM` savo antriniams procesams, bet šie į jį nereaguoja, todėl telkinys veikia tol, kol procesai sustoja dėl vienos iš anksčiau nurodytų priežasčių. Norėdami sustabdyti telkinį, procesų tvarkyklėje nustatykite sustabdymo skirtąjį laiką, kuriam pasibaigus siunčiamas `SIGKILL`.

## Kelių darbininkų lygiagretumas

Vėliavėlė `--workers=N` paleidžia N antrinių procesų naudojant `pcntl_fork()`. Kiekvienas antrinis procesas sukuria atskirą duomenų bazės ryšį ir savarankiškai apdoroja užduotis. Pirminis procesas stebi antrinius procesus ir iš naujo paleidžia užstrigusius.

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

Reikalavimai:
Turi būti įdiegti plėtiniai `pcntl` ir `posix` PHP (be `pcntl` komanda nepavyksta su klaida "pcntl extension is required for --workers=N."), o kiekvienas antrinis procesas naudoja atskirą duomenų bazės ryšį, todėl jūsų MySQL `max_connections` nustatymas turi būti pritaikytas telkiniui. Adaptyviems telkiniams (`--min-workers`/`--max-workers`) taikomi tie patys reikalavimai.

## Adaptyvūs darbininkų telkiniai

Adaptyvūs telkiniai palaiko veikiantį minimalų darbininkų skaičių ir didina arba mažina jį nustatytame intervale:

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

Pirminis procesas stebi, kiek užduočių galima paimti pasirinktame eilių rinkinyje, ir koreguoja antrinių procesų skaičių pagal šį kiekį, neviršydamas nustatytos didžiausios reikšmės. Eilei aprimus, telkinys prieš mažindamas darbininkų skaičių laukia nustatytą neveiklumo laiką, kad dėl trumpų apkrovos šuolių procesų sąrašas nebūtų nuolat keičiamas.

Telkinys didinamas atsargiai. Kai Queuety gali nuskaityti konteinerio ar pagrindinio kompiuterio atminties duomenis, jis atsisako pridėti daugiau antrinių procesų, jei nepakanka laisvos atminties dar vienam visam darbininkui.

Pirminio proceso vykdomą mastelio keitimo ciklą valdo:

| Konstanta | Aprašymas |
|---|---|
| `QUEUETY_WORKER_POOL_SCALE_INTERVAL` | Kaip dažnai pirminis procesas sinchronizuoja telkinio dydį |
| `QUEUETY_WORKER_POOL_IDLE_GRACE` | Kiek laiko eilė turi būti rami, kad telkinys galėtų sumažėti |

## Pasenusių užduočių atkūrimas

Jei darbininkas sugenda vykdydamas užduotį, ji lieka būsenos `processing`. Ilgai veikiantis darbininkas maždaug kartą per minutę tikrina, ar nėra užduočių, kurios būsenoje `processing` išbuvo ilgiau nei `QUEUETY_STALE_TIMEOUT` sekundžių. Jei pasenusiai užduočiai dar liko bandymų, pasibaigus delsai iki kito bandymo ji vykdoma iš naujo; jei visi bandymai išnaudoti, ji perkeliama į nepavykusių užduočių saugyklą, o jos darbo seka pažymima kaip nepavykusi. `--once` darbininkai ir atsarginė priemonė WP-Cron šios patikros neatlieka.

Atkurkite pasenusias užduotis rankiniu būdu:

```bash
wp queuety recover
```

## Iškrovimo režimas

Apdorokite visas laukiančias užduotis ir baikite darbą. Naudinga testavimui arba vienkartiniam paketiniam apdorojimui:

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

## Diegimas produkcinėje aplinkoje

Produkcinei aplinkai naudokite procesų tvarkyklę, kad darbininkai veiktų nuolat. Štai du įprasti būdai.

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

Įjunkite ir paleiskite:

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

### Diegimo patarimai

Kai reikia geriau izoliuoti eiles, naudokite atskirus darbininkus kiekvienai eilei. Jei darbo krūvis daugiausia tenka CPU, naudokite `--workers=N`, o jei daugiausia atliekamos I/O operacijos, geriau naudokite atskirai prižiūrimus darbininkus. Nustatykite `QUEUETY_WORKER_MAX_JOBS`, jei norite periodiškai paleisti procesus iš naujo ir atlaisvinti atmintį, o užduočių `buried` skaičių stebėkite naudodami [žiniatinklio kabliukai](https://queuety.inline0.dev/lt/docs/features/webhooks) arba [metrikos](https://queuety.inline0.dev/lt/docs/features/metrics).
