
# Workeři

Workeři jsou dlouho běžící procesy, které kontrolují databázi kvůli čekajícím úlohám, spouštějí je a posouvají workflow dál. Příkaz `wp queuety work` běží uvnitř WP-CLI, zatímco frontu si přímo nárokuje z MySQL prostřednictvím nejvhodnějšího dostupného ovladače DB Queuety.

Plugin také instaluje výchozí náhradní řešení WordPress cron, které se spouští jednou za minutu v prostředích bez přístupu k shellu. Tato stránka se věnuje vyhrazeným workerům WP-CLI, které jsou doporučeným způsobem nasazení pro vyšší propustnost.

## Spuštění workeru

```bash
wp queuety work
```

Tím se spustí jeden worker ve frontě `default`. Poběží ve smyčce: nárokuje si úlohu, provede ji a opakuje postup. Když je fronta prázdná, před další kontrolou počká `QUEUETY_WORKER_SLEEP` sekund (výchozí hodnota: 1).

### Možnosti

| Možnost | Popis |
|---|---|
| `--queue=<queue>` | Queue(s) ke zpracování, oddělené čárkami pro určení priority (výchozí: `default`) |
| `--once` | Zpracuje nejvýše jednu úlohu a skončí |
| `--workers=<n>` | Vytvoří N pracovních procesů (vyžaduje rozšíření `pcntl` a `posix`) |
| `--min-workers=<n>` | Minimální počet pracovních procesů pro adaptivní fond. Vyžaduje `--max-workers` |
| `--max-workers=<n>` | Maximální počet pracovních procesů pro adaptivní fond |

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

## Priority více front

Jeden worker může zpracovávat více front v pořadí podle priority. Předáním seznamu názvů front oddělených čárkami do `--queue` určíte jejich pořadí:

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

Worker se pokusí nárokovat úlohu z každé fronty v uvedeném pořadí. Nejprve zkontroluje `critical`. Pokud `critical` obsahuje úlohu, zpracuje ji. Pokud je `critical` prázdná, přejde k `default` a poté k `low`. Fronty s vyšší prioritou se tak vždy vyprázdní dříve než ty s nižší prioritou.

### Jak funguje řazení podle priority

Při každém průchodu se worker pokusí nárokovat úlohu z první fronty v seznamu. Pokud je prázdná nebo pozastavená, přejde k další a pokračuje, dokud úlohu nenajde nebo nevyčerpá celý seznam. Pokud žádnou úlohu nenajde, počká a pokusí se znovu. Jde o striktní model priorit, takže stálý přísun úloh `critical` způsobí, že fronty `default` a `low` budou strádat. Pokud potřebujete zaručit průchodnost front s nižší prioritou, použijte vyhrazené workery.

### Použití více front v PHP

Metody `Worker::run()` a `Worker::flush()` přijímají řetězec nebo pole:

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

### Strategie nasazení

**Vyhrazené workery pro každou frontu** vám poskytnou plnou kontrolu nad souběžností a izolací. Každá fronta má vlastní proces workeru process(es) a jiné fronty ji nemohou odsunout na vedlejší kolej:

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

**Pořadí priorit s jedním workerem** se spravuje snadněji a hodí se, když fronty s nižší prioritou mohou snést zpoždění:

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

Můžete kombinovat oba přístupy: vyhradit workery pro `critical`, abyste zaručili průchodnost, a pro vše ostatní použít workery s řazením podle priority:

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

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

## Přijímání úloh s ohledem na prostředky

Workeři pouze nenárokují další čekající řádek. Než se nárokovaná úloha spustí, může Queuety provést hrubou kontrolu přijetí na základě skupiny souběžnosti úlohy a nedávného profilu spuštění dané obslužné rutiny.

Širší model a jeho propojení s metadaty úloh a rozpočty workflow popisuje stránka [Správa prostředků](https://queuety.inline0.dev/cs/docs/features/resource-management).

Skupina souběžnosti umožňuje několika obslužným rutinám nebo třídám úloh sdílet společný limit. Pokud několika náročným poskytovatelům nastavíte stejnou skupinu a limit, worker uvolní nově nárokovanou práci místo jejího spuštění, jakmile skupina dosáhne limitu. Nezávislé fronty tak nezahlcují jeden navazující systém jen proto, že je k dispozici více nečinných workerů.

Nedávné protokoly spuštění také slouží k vytvoření jednoduchého profilu pro přijímání úloh. Když je tato funkce zapnutá, Queuety se podívá na nedávnou průměrnou dobu běhu a špičkovou spotřebu paměti obslužné rutiny, kterou se chystá spustit. Pokud se aktuální worker blíží nastavenému limitu paměti, fronta nebo skupina poskytovatelů dosáhla váženého rozpočtu, kontejneru podle odhadu nezbývá dost paměti na pozorovaný profil rutiny nebo se běh ve stylu `--once` blíží časovému limitu, Queuety úlohu odloží místo spuštění práce, která se pravděpodobně nedokončí bez problémů.

Zásady nastavujete v definici práce, nikoli v příkazu workeru:

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

Stejná metadata lze připojit k odesílatelným třídám úloh pomocí veřejných vlastností nebo k jednotlivému odeslání prostřednictvím `PendingJob::concurrency_group()` a `PendingJob::cost_units()`.

Profil přijímání úloh na straně workeru se řídí těmito konstantami:

| Konstantní hodnota | Popis |
|---|---|
| `QUEUETY_RESOURCE_ADMISSION` | Zapnutí nebo vypnutí kontrol přijetí na základě profilu |
| `QUEUETY_RESOURCE_PROFILE_WINDOW_MINUTES` | Jak daleko do minulosti hledat při sestavování nedávných profilů obslužných rutin |
| `QUEUETY_RESOURCE_PROFILE_TTL` | Doba platnosti mezipaměti nedávných profilů obslužných rutin |
| `QUEUETY_RESOURCE_MEMORY_HEADROOM_MB` | Rezervní paměť před přijetím další úlohy |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS` | Zapnutí nebo vypnutí orientačních kontrol paměti kontejneru nebo hostitele |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_HEADROOM_MB` | Rezervní systémová paměť před přijetím další úlohy |
| `QUEUETY_RESOURCE_QUEUE_COST_BUDGETS` | Vážené rozpočty nákladů podle názvu fronty |
| `QUEUETY_RESOURCE_GROUP_COST_BUDGETS` | Vážené rozpočty nákladů podle `concurrency_group` |
| `QUEUETY_RESOURCE_TIME_HEADROOM_MS` | Rezervní časová rezerva pro jednorázová spuštění workeru |

## Životní cyklus workeru

Worker se po dokončení aktuální úlohy bezpečně zastaví, když nastane kterákoli z těchto podmínek:

| Podmínka | Nastavení |
|---|---|
| Maximální počet zpracovaných úloh | `QUEUETY_WORKER_MAX_JOBS` (výchozí hodnota: 1000) |
| Překročení limitu paměti | `QUEUETY_WORKER_MAX_MEMORY` (výchozí hodnota: 128 MB) |

Po zastavení se worker korektně ukončí. V produkci jej správce procesů automaticky znovu spustí.

Signály se zatím nezpracovávají bezpečně ([#4](https://github.com/inline0/queuety/issues/4)). Samostatný proces `wp queuety work` nenastavuje obslužnou rutinu signálů, takže `SIGTERM` nebo `SIGINT` (Ctrl+C) jej okamžitě ukončí, i uprostřed úlohy. Úloha zůstane ve stavu `processing`, dokud ji obnova zastaralých úloh po `QUEUETY_STALE_TIMEOUT` sekundách neresetuje, proto zajistěte, aby bylo bezpečné ji zopakovat. Pool workerů předává svým potomkům signál `SIGTERM`, ale ti na něj nereagují, takže pool běží dál, dokud se nezastaví z některého z výše uvedených důvodů. Chcete-li pool zastavit, nastavte správci procesů časový limit, po jehož uplynutí odešle `SIGKILL`.

## Souběžné zpracování více workery

Příznak `--workers=N` spustí N podřízených procesů pomocí `pcntl_fork()`. Každý potomek vytvoří vlastní databázové připojení a zpracovává úlohy nezávisle. Rodičovský proces sleduje potomky a restartuje ty, které havarují.

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

Požadavky:
Musí být nainstalována rozšíření `pcntl` a `posix` PHP (bez `pcntl` příkaz selže s hlášením „je vyžadováno rozšíření pcntl pro --workers=N.“) a každý podřízený proces používá vlastní databázové připojení, takže nastavení MySQL `max_connections` musí počítat s celým fondem. Adaptivní fondy (`--min-workers`/`--max-workers`) mají stejné požadavky.

## Adaptivní fondy pracovních procesů

Adaptivní fondy udržují minimální počet připravených pracovních procesů a poté se zvětšují a zmenšují v rámci nastaveného rozsahu:

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

Nadřazený proces sleduje počet čekajících úloh připravených ke zpracování ve vybrané sadě front a upravuje počet podřízených procesů podle tohoto počtu až do nastaveného maxima. Když se fronta zklidní, fond před zmenšením čeká po dobu nastavené prodlevy nečinnosti, aby krátké nárazové zatížení hned nezměnilo seznam procesů.

Zvyšování kapacity je i nadále opatrné. Když Queuety dokáže číst údaje o paměti kontejneru nebo hostitele, odmítne přidat další podřízené procesy, pokud zbývající paměť nestačí na celý rozsah dalšího pracovního procesu.

Smyčku škálování na straně nadřazeného procesu ovládají:

| Konstanta | Popis |
|---|---|
| `QUEUETY_WORKER_POOL_SCALE_INTERVAL` | Jak často nadřazený proces upravuje velikost fondu |
| `QUEUETY_WORKER_POOL_IDLE_GRACE` | Jak dlouho musí fronta zůstat klidná, než se fond zmenší |

## Obnova zastaralých úloh

Pokud pracovní proces při zpracování úlohy spadne, úloha zůstane ve stavu `processing`. Dlouho běžící pracovní proces přibližně jednou za minutu kontroluje úlohy, které jsou ve stavu `processing` déle než `QUEUETY_STALE_TIMEOUT` sekund. Zastaralá úloha s nevyčerpanými pokusy se po prodlevě mezi pokusy zařadí znovu ke zpracování; úloha, u které jsou vyčerpány všechny pokusy, se odloží a její pracovní postup se označí jako neúspěšný. Tuto kontrolu neprovádějí pracovní procesy `--once` ani záložní řešení WP-Cron.

Obnovte zastaralé úlohy ručně:

```bash
wp queuety recover
```

## Režim vyprázdnění fronty

Zpracuje všechny čekající úlohy a ukončí se. Hodí se pro testování nebo jednorázové dávkové zpracování:

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

## Nasazení do produkčního prostředí

V produkčním prostředí použijte správce procesů, který bude udržovat pracovní procesy spuštěné. Zde jsou dva běžné způsoby.

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

Povolte a spusťte:

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

### Tipy k nasazení

Pokud potřebujete důkladnější izolaci, spusťte samostatné pracovní procesy pro jednotlivé fronty. Když je úloha náročná na CPU, použijte `--workers=N`; u úloh převážně náročných na I/O dejte přednost samostatně spravovaným pracovním procesům. Pokud chcete pravidelnými restarty uvolňovat paměť, nastavte `QUEUETY_WORKER_MAX_JOBS` a sledujte počet `buried` prostřednictvím [webhooků](https://queuety.inline0.dev/cs/docs/features/webhooks) nebo [metrik](https://queuety.inline0.dev/cs/docs/features/metrics).
