
# Primeiros passos

## Instalação

### Requisitos

- PHP 8.2 ou posterior e WordPress 6.4 ou posterior
- MySQL 8.0+ ou MariaDB 10.6+. Os workers reivindicam jobs e agendamentos vencidos com `SELECT ... FOR UPDATE SKIP LOCKED`, que servidores mais antigos rejeitam com um erro de sintaxe.
- `mysqli` ou `pdo_mysql` (veja abaixo)
- WP-CLI no servidor se você executar workers dedicados com `wp queuety work`
- As extensões `pcntl` e `posix` PHP se você executar pools de workers com `--workers` ou `--min-workers`/`--max-workers`

Queuety requer `mysqli` ou `pdo_mysql` no runtime PHP que carrega WordPress e WP-CLI. Ele escolhe o driver automaticamente, dando preferência a `mysqli` em runtimes WordPress e mantendo `pdo_mysql` disponível para uso direto/independente do runtime.

Se você quiser usar o runtime com suporte a DB sem a camada de plugin WordPress, consulte [Uso independente](https://queuety.inline0.dev/pt/docs/features/standalone-use). Esse caminho usa a mesma conexão e as mesmas tabelas do runtime, mas não inclui as pontes de hooks WordPress nem o registro WP-CLI.

### Do arquivo zip da versão

Cada versão [GitHub](https://github.com/inline0/queuety/releases) tem um artefato `queuety.zip`: o plugin com suas dependências Composer já instaladas. Instale a versão mais recente com WP-CLI:

```bash
wp plugin install https://github.com/inline0/queuety/releases/latest/download/queuety.zip --activate
```

Ou baixe o zip e envie-o em Plugins > Adicionar novo > Enviar plugin. Esse é o caminho mais simples para um site WordPress comum.

### Via Composer para Composer gerenciado por WordPress

```bash
composer require queuety/queuety
```

Em seguida, ative o plugin:

```bash
wp plugin activate queuety
```

O tipo do pacote é `wordpress-plugin`. Composer o coloca no diretório de plugins somente quando o projeto exige `composer/installers` e mapeia esse tipo para um caminho de instalação, como Bedrock faz; além disso, o projeto deve carregar seu próprio `vendor/autoload.php` (Bedrock também faz isso). Sem `composer/installers`, Composer o instala em `vendor/queuety/queuety`, onde WordPress não o encontra. Portanto, use o arquivo zip da versão em uma instalação simples de WordPress.

### Do código-fonte durante o desenvolvimento

Coloque o repositório em `wp-content/plugins/queuety` e instale as dependências PHP:

```bash
composer install
wp plugin activate queuety
```

Na ativação, Queuety cria suas tabelas de banco de dados (`queuety_jobs`, `queuety_workflows`, `queuety_logs`, `queuety_schedules`, `queuety_queue_states`, `queuety_webhooks`, `queuety_locks`, `queuety_signals`, `queuety_workflow_dependencies`, `queuety_workflow_dispatch_keys`, `queuety_batches`, `queuety_chunks`, `queuety_workflow_events`, `queuety_artifacts`, `queuety_state_machines`, `queuety_state_machine_events`) para que os workers possam reivindicar jobs diretamente de MySQL.

Por padrão, o plugin também agenda um worker de execução única por meio de WordPress cron a cada minuto para a fila `default`. Isso oferece uma configuração básica sem shell para jobs e fluxos de trabalho que permanecem em `default`, desde que WordPress cron esteja em execução. Cada execução processa no máximo um job e não executa agendamentos recorrentes, recupera jobs obsoletos nem verifica prazos de fluxos de trabalho; essas tarefas só são executadas em um processo `wp queuety work` de longa duração ([#14](https://github.com/inline0/queuety/issues/14)). Para filas personalizadas, agendamentos recorrentes, menor latência ou cargas mais pesadas, migre para processos `wp queuety work` dedicados.

## Configuração

Todas as constantes são opcionais. Defina-as em `wp-config.php` antes de carregar o plugin ou antes de Queuety iniciar em uma instalação incorporada no estilo de tema:

| Constante | Padrão | Descrição |
|---|---|---|
| `QUEUETY_RETENTION_DAYS` | `7` | Idade padrão em dias para `wp queuety purge` e `Queuety::purge()`. Nada é removido automaticamente |
| `QUEUETY_LOG_RETENTION_DAYS` | `0` | Lida por `Config::log_retention_days()`, mas ainda não é usada; os logs são mantidos até você chamar `Queuety::purge_logs()` ([#15](https://github.com/inline0/queuety/issues/15)) |
| `QUEUETY_MAX_EXECUTION_TIME` | `300` | Máximo de segundos por job antes do tempo limite (ainda não aplicado; consulte [Jobs](https://queuety.inline0.dev/pt/docs/jobs#timeout)) |
| `QUEUETY_WORKER_SLEEP` | `1` | Segundos de espera quando a fila está vazia |
| `QUEUETY_WORKER_MAX_JOBS` | `1000` | Número máximo de jobs antes de reiniciar o worker |
| `QUEUETY_WORKER_MAX_MEMORY` | `128` | Máximo de MB antes de reiniciar o worker |
| `QUEUETY_RETRY_BACKOFF` | `exponential` | Estratégia de espera progressiva: `exponential`, `linear` ou `fixed` |
| `QUEUETY_STALE_TIMEOUT` | `600` | Segundos até a recuperação de jobs travados |
| `QUEUETY_CACHE_TTL` | `5` | TTL padrão do cache em segundos |
| `QUEUETY_DEBUG` | `false` | Ativa o registro detalhado do worker |
| `QUEUETY_CLI_COMMAND` | `queuety` | Nome do comando raiz WP-CLI |
| `QUEUETY_TABLE_PREFIX` | `queuety_` | Nome base compartilhado por todas as tabelas Queuety após o prefixo do banco de dados WordPress |
| `QUEUETY_TABLE_JOBS` | `queuety_jobs` | Nome da tabela de jobs |
| `QUEUETY_TABLE_WORKFLOWS` | `queuety_workflows` | Nome da tabela de fluxos de trabalho |
| `QUEUETY_TABLE_LOGS` | `queuety_logs` | Nome da tabela de logs |
| `QUEUETY_TABLE_SCHEDULES` | `queuety_schedules` | Nome da tabela de agendamentos |
| `QUEUETY_TABLE_SIGNALS` | `queuety_signals` | Nome da tabela de sinais |
| `QUEUETY_TABLE_WORKFLOW_DEPENDENCIES` | `queuety_workflow_dependencies` | Nome da tabela de dependências pendentes de fluxos de trabalho |
| `QUEUETY_TABLE_WORKFLOW_DISPATCH_KEYS` | `queuety_workflow_dispatch_keys` | Nome da tabela de idempotência de fluxos de trabalho duráveis |
| `QUEUETY_TABLE_CHUNKS` | `queuety_chunks` | Nome da tabela de partes de dados em fluxo |
| `QUEUETY_TABLE_QUEUE_STATES` | `queuety_queue_states` | Nome da tabela de estados das filas |
| `QUEUETY_TABLE_WEBHOOKS` | `queuety_webhooks` | Nome da tabela de webhooks |
| `QUEUETY_TABLE_LOCKS` | `queuety_locks` | Nome da tabela de bloqueios |
| `QUEUETY_TABLE_BATCHES` | `queuety_batches` | Nome da tabela de lotes |
| `QUEUETY_TABLE_WORKFLOW_EVENTS` | `queuety_workflow_events` | Nome da tabela de logs de eventos de fluxos de trabalho |
| `QUEUETY_TABLE_ARTIFACTS` | `queuety_artifacts` | Nome da tabela de artefatos de fluxos de trabalho |
| `QUEUETY_TABLE_STATE_MACHINES` | `queuety_state_machines` | Nome da tabela de máquinas de estado |
| `QUEUETY_TABLE_STATE_MACHINE_EVENTS` | `queuety_state_machine_events` | Nome da tabela de logs de eventos de máquinas de estado |
| `QUEUETY_DB_DRIVER` | `auto` | Driver MySQL: `auto`, `mysqli` ou `pdo`. `auto` dá preferência a `mysqli` quando WordPress está carregado; caso contrário, a `pdo_mysql` e, depois, a `mysqli` |

As constantes de admissão de recursos e do pool adaptativo (`QUEUETY_RESOURCE_*`, `QUEUETY_WORKER_POOL_*`) estão listadas na página [Workers](https://queuety.inline0.dev/pt/docs/features/workers).

`QUEUETY_TABLE_PREFIX` altera apenas a parte Queuety dos nomes das tabelas. O prefixo do banco de dados WordPress continua envolvendo o resultado, então `$wpdb->prefix = 'wp_'` e `QUEUETY_TABLE_PREFIX = 'themequeue_'` produzem tabelas como `wp_themequeue_jobs`. As constantes `QUEUETY_TABLE_*` explícitas ainda prevalecem para tabelas individuais.

Conexões independentes também podem definir o prefixo da tabela Queuety por conexão:

```php
$conn = new Connection(
    host: '127.0.0.1:3306',
    dbname: 'wordpress',
    user: 'root',
    password: 'secret',
    prefix: 'wp_',
    table_prefix: 'themequeue_',
);
```

Isso mantém intacto o prefixo do banco de dados WordPress e altera apenas o segmento da tabela Queuety.

## Seu primeiro job

Crie uma classe de manipulador que implemente a interface `Handler`:

```php
use Queuety\Handler;

class SendEmailHandler implements Handler {
    public function handle( array $payload ): void {
        wp_mail( $payload['to'], $payload['subject'], $payload['body'] );
    }

    public function config(): array {
        return [
            'queue'           => 'emails',
            'max_attempts'    => 5,
        ];
    }
}
```

Registre-a e envie o job:

```php
use Queuety\Queuety;

Queuety::register( 'send_email', SendEmailHandler::class );

Queuety::dispatch( 'send_email', [
    'to'      => 'user@example.com',
    'subject' => 'Welcome',
    'body'    => 'Hello from Queuety!',
] );
```

Ou use a classe de job moderna que pode ser enviada:

```php
use Queuety\Contracts\Job;
use Queuety\Dispatchable;

readonly class SendEmailJob implements Job {
    use Dispatchable;

    public function __construct(
        public string $to,
        public string $subject,
        public string $body,
    ) {}

    public function handle(): void {
        wp_mail( $this->to, $this->subject, $this->body );
    }
}

SendEmailJob::dispatch( 'user@example.com', 'Welcome', 'Hello from Queuety!' );
```

## Seu primeiro fluxo de trabalho

Defina manipuladores de etapas que implementem a interface `Step`:

```php
use Queuety\Step;

class FetchDataHandler implements Step {
    public function handle( array $state ): array {
        $user = get_user_by( 'ID', $state['user_id'] );
        return [ 'user_name' => $user->display_name ];
    }

    public function config(): array {
        return [];
    }
}

class CallLLMHandler implements Step {
    public function handle( array $state ): array {
        $response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', [
            'body' => json_encode( [ 'prompt' => "Generate report for {$state['user_name']}" ] ),
        ] );
        return [ 'llm_response' => wp_remote_retrieve_body( $response ) ];
    }

    public function config(): array {
        return [ 'max_attempts' => 5 ];
    }
}

class FormatOutputHandler implements Step {
    public function handle( array $state ): array {
        $url = save_report( $state['user_name'], $state['llm_response'] );
        return [ 'report_url' => $url ];
    }

    public function config(): array {
        return [];
    }
}
```

Envie o fluxo de trabalho:

```php
$workflow_id = Queuety::workflow( 'generate_report' )
    ->then( FetchDataHandler::class )
    ->then( CallLLMHandler::class )
    ->then( FormatOutputHandler::class )
    ->dispatch( [ 'user_id' => 42 ] );
```

## Inicie um worker

```bash
wp queuety work
```

O worker verifica se há jobs pendentes, executa-os, avança os fluxos de trabalho e aguarda quando a fila está vazia. Pressione `Ctrl+C` para parar; isso encerra o processo imediatamente, mesmo no meio de um job (consulte [Workers](https://queuety.inline0.dev/pt/docs/features/workers#worker-lifecycle)).

O `SendEmailHandler` acima envia seus jobs para a fila `emails` por meio de `config()`, portanto um worker em `default` não os coleta. Informe o nome de cada fila que usar:

```bash
wp queuety work --queue=emails,default
```

Se você não executar um worker dedicado, Queuety ainda oferece a alternativa padrão WordPress cron, executada uma vez por minuto e descrita acima, limitada à fila `default` e a um job por execução. O worker dedicado oferece maior capacidade de processamento e menor latência.

Em produção, execute vários workers:

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

Processe várias filas com ordenação por prioridade:

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

## Próximos passos

- [Jobs](https://queuety.inline0.dev/pt/docs/jobs) para o guia completo de envio e manipulação de jobs
- [Workflows](https://queuety.inline0.dev/pt/docs/workflows) para cadeias, etapas paralelas, ramificações condicionais e execução de fluxos de trabalho
- [Middleware](https://queuety.inline0.dev/pt/docs/features/middleware) para limitação de taxa, controle de fluxo e lógica de pipeline personalizada
- [Processamento em lote](https://queuety.inline0.dev/pt/docs/features/batching) para enviar grupos de jobs com callbacks
- [Etapas em fluxo](https://queuety.inline0.dev/pt/docs/workflows/streaming) para persistir dados transmitidos em partes, uma por vez
- [Agendamento](https://queuety.inline0.dev/pt/docs/features/scheduling) para jobs recorrentes
- [Cache](https://queuety.inline0.dev/pt/docs/features/caching) para a camada de cache conectável
- [Testes](https://queuety.inline0.dev/pt/docs/features/testing) para QueueFake e asserções de teste
- [ReferênciaCLI](https://queuety.inline0.dev/pt/docs/cli) para todos os comandos disponíveis
- [AcessoPHP APIprogramático](https://queuety.inline0.dev/pt/docs/api)
