
# Workers

Workers são processos de longa duração que consultam o banco de dados em busca de tarefas pendentes, executam-nas e avançam os fluxos de trabalho. O comando `wp queuety work` é executado dentro de WP-CLI enquanto a fila é reivindicada diretamente de MySQL pelo melhor driver de banco de dados Queuety disponível.

O plugin também instala uma alternativa padrão de WordPress cron, executada uma vez por minuto, para ambientes sem acesso ao shell. Esta página aborda workers WP-CLI dedicados, o modo de implantação recomendado para maior throughput.

## Iniciando um worker

```bash
wp queuety work
```

Isso inicia um único worker na fila `default`. Ele executa em loop: reivindica uma tarefa, executa-a e repete. Quando a fila está vazia, aguarda `QUEUETY_WORKER_SLEEP` segundos (padrão: 1) antes de consultá-la novamente.

### Opções

| Opção | Descrição |
|---|---|
| `--queue=<queue>` | Queue(s) a processar, separados por vírgulas para definir a ordem de prioridade (padrão: `default`) |
| `--once` | Processa no máximo uma tarefa e encerra |
| `--workers=<n>` | Cria N processos worker (requer as extensões `pcntl` e `posix`) |
| `--min-workers=<n>` | Número mínimo de workers para um pool adaptável. Requer `--max-workers` |
| `--max-workers=<n>` | Número máximo de workers para um pool adaptável |

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

## Prioridades entre várias filas

Um único worker pode processar várias filas em ordem de prioridade. Passe uma lista de nomes de filas separados por vírgulas para `--queue`:

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

O worker tenta reivindicar uma tarefa de cada fila na ordem informada. Ele verifica `critical` primeiro. Se `critical` tiver uma tarefa, ele a processa. Se `critical` estiver vazia, passa para `default` e, em seguida, para `low`. Isso significa que as filas de maior prioridade são sempre esvaziadas antes das de menor prioridade.

### Como funciona a ordem de prioridade

A cada iteração, o worker tenta reivindicar uma tarefa da primeira fila da lista. Se essa fila estiver vazia ou pausada, passa para a próxima e continua até encontrar uma tarefa ou percorrer a lista toda. Se nenhuma tarefa for encontrada, o worker aguarda e tenta novamente. Esse modelo de prioridade estrita significa que um fluxo constante de tarefas `critical` deixará as filas `default` e `low` sem processamento. Se filas de menor prioridade precisarem de throughput garantido, use workers dedicados.

### Usando várias filas em PHP

Os métodos `Worker::run()` e `Worker::flush()` aceitam uma string ou um 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' );
```

### Estratégias de implantação

**Workers dedicados por fila** oferecem controle total sobre a concorrência e o isolamento. Cada fila recebe seu próprio process(es) de worker e não pode ficar sem processamento por causa de outras filas:

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

**A ordem de prioridade com um único worker** é mais simples de gerenciar e funciona bem quando filas de menor prioridade podem tolerar atrasos:

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

Você também pode combinar as duas abordagens: workers dedicados para `critical` garantem o throughput, enquanto um worker com filas ordenadas por prioridade processa todo o restante:

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

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

## Admissão com base nos recursos

Workers fazem mais do que simplesmente reivindicar a próxima linha pendente. Antes de iniciar uma tarefa reivindicada, Queuety pode aplicar verificações gerais de admissão com base no grupo de concorrência da tarefa e no perfil recente de execução daquele handler.

Para conhecer o modelo mais amplo, incluindo como ele se relaciona aos metadados de tarefas e aos orçamentos dos fluxos de trabalho, consulte [Gerenciamento de recursos](https://queuety.inline0.dev/pt/docs/features/resource-management).

Um grupo de concorrência permite que vários handlers ou classes de tarefas compartilhem um limite. Se você atribuir o mesmo grupo e limite a vários provedores que consomem muitos recursos, o worker liberará o trabalho recém-reivindicado em vez de iniciá-lo quando o grupo atingir o limite. Isso impede que filas independentes sobrecarreguem um mesmo sistema downstream só porque há vários workers ociosos.

Os registros de execução recentes também alimentam um perfil simples de admissão. Quando a admissão por recursos está ativada, Queuety consulta a duração média recente e o pico de memória do handler que está prestes a executar. Se o worker atual já estiver perto do limite de memória configurado, uma fila ou grupo de provedores já tiver atingido seu orçamento ponderado, o contêiner atual aparentemente não tiver memória livre suficiente para o perfil observado do handler ou uma execução no estilo `--once` estiver perto do seu limite de tempo, Queuety adia a tarefa em vez de iniciar um trabalho com poucas chances de terminar corretamente.

Você ativa a política na definição do trabalho, e não no comando do worker:

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

Os mesmos metadados podem ser atribuídos a classes de tarefa despacháveis por meio de propriedades públicas ou a um despacho individual usando `PendingJob::concurrency_group()` e `PendingJob::cost_units()`.

O perfil de admissão do worker é controlado por estas constantes:

| Constante | Descrição |
|---|---|
| `QUEUETY_RESOURCE_ADMISSION` | Ativa ou desativa verificações de admissão baseadas em perfil |
| `QUEUETY_RESOURCE_PROFILE_WINDOW_MINUTES` | Período de consulta usado para criar perfis recentes de handlers |
| `QUEUETY_RESOURCE_PROFILE_TTL` | TTL do cache dos perfis recentes de handlers |
| `QUEUETY_RESOURCE_MEMORY_HEADROOM_MB` | Margem de memória reservada antes de admitir outra tarefa |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS` | Ativa ou desativa verificações de melhor esforço da memória do contêiner ou host |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_HEADROOM_MB` | Margem de memória do sistema reservada antes de admitir outra tarefa |
| `QUEUETY_RESOURCE_QUEUE_COST_BUDGETS` | Orçamentos de custo ponderado definidos por nome de fila |
| `QUEUETY_RESOURCE_GROUP_COST_BUDGETS` | Orçamentos de custo ponderado definidos por `concurrency_group` |
| `QUEUETY_RESOURCE_TIME_HEADROOM_MS` | Margem de tempo reservada para execuções de worker em uma única execução |

## Ciclo de vida do worker

Um worker é encerrado de forma gradual, após concluir a tarefa atual, quando qualquer uma destas condições é atendida:

| Condição | Configuração |
|---|---|
| Número máximo de tarefas processadas | `QUEUETY_WORKER_MAX_JOBS` (padrão: 1000) |
| Limite de memória excedido | `QUEUETY_WORKER_MAX_MEMORY` (padrão: 128 MB) |

Após parar, o worker é encerrado corretamente. Em produção, um gerenciador de processos o reinicia automaticamente.

Os sinais ainda não são tratados de forma gradual ([#4](https://github.com/inline0/queuety/issues/4)). Um processo `wp queuety work` único não instala um handler de sinal; portanto, `SIGTERM` ou `SIGINT` (Ctrl+C) o encerra imediatamente, mesmo durante uma tarefa. Essa tarefa permanece `processing` até que a recuperação de tarefas obsoletas a redefina após `QUEUETY_STALE_TIMEOUT` segundos; por isso, mantenha os handlers seguros para novas tentativas. Um pool de workers encaminha `SIGTERM` aos processos filhos, mas eles não agem sobre o sinal. Assim, o pool continua em execução até que parem por um dos motivos acima. Para interromper um pool, configure um tempo limite de parada no gerenciador de processos; depois desse prazo, ele enviará `SIGKILL`.

## Concorrência com vários workers

A opção `--workers=N` cria N processos filhos usando `pcntl_fork()`. Cada filho cria sua própria conexão com o banco de dados e processa tarefas de forma independente. O processo pai monitora os filhos e reinicia os que falharem.

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

Requisitos:
As extensões `pcntl` e `posix` PHP precisam estar instaladas (sem `pcntl`, o comando falha com "pcntl extension is required for --workers=N."), e cada filho usa sua própria conexão com o banco de dados; portanto, a configuração MySQL `max_connections` precisa comportar o pool. Pools adaptáveis (`--min-workers`/`--max-workers`) têm os mesmos requisitos.

## Pools de workers adaptáveis

Os pools adaptáveis mantêm um número mínimo de workers prontos e aumentam ou diminuem dentro do intervalo configurado:

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

O processo pai monitora o backlog reivindicável no conjunto de filas selecionado e ajusta o número de processos filhos de acordo com esse backlog, respeitando o máximo configurado. Quando a fila fica mais tranquila, o pool aguarda o período de tolerância à ociosidade antes de reduzir o número de workers, evitando que picos breves alterem imediatamente a lista de processos.

O aumento ainda é conservador. Quando Queuety consegue ler as métricas de memória do contêiner ou host, ele se recusa a adicionar processos filhos se não houver memória livre suficiente para outro worker completo.

O loop de ajuste de escala do processo pai é controlado por:

| Constante | Descrição |
|---|---|
| `QUEUETY_WORKER_POOL_SCALE_INTERVAL` | Intervalo entre ajustes do tamanho do pool pelo processo pai |
| `QUEUETY_WORKER_POOL_IDLE_GRACE` | Tempo durante o qual o backlog precisa permanecer reduzido antes de diminuir o pool |

## Recuperação de tarefas obsoletas

Se um worker falhar durante o processamento de uma tarefa, ela ficará com o status `processing`. Um worker de longa duração verifica aproximadamente uma vez por minuto se há tarefas que permanecem em `processing` por mais de `QUEUETY_STALE_TIMEOUT` segundos. Uma tarefa obsoleta com tentativas restantes é processada novamente após o atraso de espera; uma tarefa que esgotou as tentativas é colocada em espera, e seu fluxo de trabalho é marcado como falho. Workers `--once` e a alternativa WP-Cron não executam essa verificação.

Recupere tarefas obsoletas manualmente:

```bash
wp queuety recover
```

## Modo de processamento em lote

Processa todas as tarefas pendentes e encerra. Útil para testes ou processamento pontual em lote:

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

## Implantação em produção

Em produção, use um gerenciador de processos para manter os workers em execução. Estas são duas abordagens comuns.

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

Ative e inicie:

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

### Dicas de implantação

Execute workers separados para filas distintas quando precisar de maior isolamento. Use `--workers=N` quando a carga for limitada pela CPU e prefira workers supervisionados individualmente quando ela depender principalmente de E/S. Defina `QUEUETY_WORKER_MAX_JOBS` se quiser reinicializações periódicas para liberar memória e monitore a contagem de `buried` por meio de [webhooks](https://queuety.inline0.dev/pt/docs/features/webhooks) ou [métricas](https://queuety.inline0.dev/pt/docs/features/metrics).
