Pular para o conteúdo

Tarefas

As tarefas são a unidade central de trabalho em Queuety. Despache uma tarefa com o nome de um manipulador e uma carga útil; um worker a coleta e a executa em segundo plano.

Despachando tarefas

PHP
use Queuety\Queuety;

Queuety::dispatch( 'send_email', [ 'to' => 'user@example.com' ] );

dispatch() retorna um construtor PendingJob. Você pode encadear opções antes do despacho automático:

PHP
use Queuety\Enums\Priority;

Queuety::dispatch( 'send_email', [ 'to' => 'user@example.com' ] )
    ->on_queue( 'emails' )
    ->with_priority( Priority::High )
    ->delay( 300 )
    ->max_attempts( 5 );

Para obter o ID da tarefa imediatamente, chame ->id():

PHP
$job_id = Queuety::dispatch( 'send_email', $payload )->id();

Escrevendo manipuladores

Um manipulador é qualquer classe que implementa a interface Queuety\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,
            'backoff'         => 'exponential',
        ];
    }
}

O método handle() recebe a carga útil da tarefa e executa o trabalho. O método config() retorna valores padrão opcionais:

Chave Tipo Descrição
queue string Nome padrão da fila
max_attempts int Número máximo de execuções, contando a primeira, antes de a tarefa ser arquivada
backoff string Estratégia de espera entre tentativas: exponential, linear ou fixed
rate_limit array Limite de taxa como [max_executions, window_seconds]
concurrency_group string Grupo compartilhado de admissão de workers para manipuladores caros
concurrency_limit int Número máximo de tarefas simultâneas em processamento nesse grupo
cost_units int Custo relativo de execução usado por orçamentos ponderados de filas ou provedores, orçamentos de fluxo de trabalho e heurísticas de admissão

Essas chaves de recursos fazem parte do modelo mais amplo de QueuetyGerenciamento de recursos, em que metadados de tarefas, orçamentos de fluxos de trabalho e admissão de workers atuam em conjunto.

Registre o manipulador:

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

Ou use os atributos PHP para registro automático.

Prioridade

As tarefas têm quatro níveis de prioridade. Os workers obtêm primeiro as tarefas de prioridade mais alta.

PHP
use Queuety\Enums\Priority;

Queuety::dispatch( 'handler', $payload )->with_priority( Priority::Urgent );
Nível Valor Descrição
Priority::Low 0 Padrão. Trabalho em segundo plano que pode esperar.
Priority::Normal 1 Prioridade padrão.
Priority::High 2 Processada antes de Baixa e Normal.
Priority::Urgent 3 Processada primeiro. Use com moderação.

Atraso

Atrase uma tarefa para que fique disponível somente após o número de segundos especificado:

PHP
Queuety::dispatch( 'send_reminder', $payload )->delay( 3600 ); // 1 hour

A tarefa é inserida imediatamente, mas os workers só a obterão quando o atraso terminar.

Tarefas únicas

Evite despachos duplicados para o mesmo manipulador e carga útil. Se já existir uma tarefa pendente ou em processamento com o mesmo manipulador e a mesma carga útil, o ID da tarefa existente será retornado em vez de criar uma nova.

PHP
Queuety::dispatch( 'sync_inventory', [ 'sku' => 'ABC-123' ] )->unique();

Dependências entre tarefas

Uma tarefa pode depender de outra. Um worker só a obterá quando a dependência for concluída.

PHP
$first_id = Queuety::dispatch( 'import_data', $payload )->id();

Queuety::dispatch( 'send_notification', [ 'import_id' => $first_id ] )
    ->after( $first_id );

Despacho em lote

Despache várias tarefas em um único INSERT de várias linhas para obter o máximo de processamento:

PHP
$job_ids = Queuety::batch( [
    [ 'handler' => 'send_email', 'payload' => [ 'to' => 'a@example.com' ] ],
    [ 'handler' => 'send_email', 'payload' => [ 'to' => 'b@example.com' ] ],
    [ 'handler' => 'send_email', 'payload' => [ 'to' => 'c@example.com' ] ],
] );

Cada item pode incluir chaves opcionais: queue, priority, delay, max_attempts.

Novas tentativas e espera progressiva

Quando uma tarefa lança uma exceção, Queuety a devolve a pending com um available_at atrasado até que tenha sido executada max_attempts vezes no total (a primeira execução conta, portanto, max_attempts( 3 ) significa até duas novas tentativas). O atraso antes de cada nova tentativa é determinado pela estratégia de espera progressiva, em que attempt é o número da execução que acabou de falhar:

Estratégia Fórmula do atraso Exemplo (após as execuções 1, 2, 3)
exponential 2^attempt * 30 segundos, limitado a 3600 60s, 120s, 240s
linear attempt * 60 segundos 60s, 120s, 180s
fixed 60 segundos 60s, 60s, 60s

Defina o padrão global em wp-config.php:

PHP
define( 'QUEUETY_RETRY_BACKOFF', 'linear' );

Ou por manipulador em config():

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

Ou por despacho:

PHP
Queuety::dispatch( 'handler', $payload )->max_attempts( 10 );

Jobs em espera

Depois de esgotar todas as tentativas, uma tarefa é marcada como arquivada. As tarefas arquivadas permanecem no banco de dados para inspeção, mas não são processadas. Você pode tentar executá-las novamente manualmente. Uma nova tentativa manual torna a tarefa pending novamente, sem redefinir a contagem de tentativas; assim, uma tarefa arquivada que seja tentada novamente terá mais uma execução e será arquivada de novo se essa execução falhar:

PHP
// Retry a specific buried job
Queuety::retry( $job_id );

// Retry all buried jobs
$count = Queuety::retry_buried();

Ou por meio de CLI:

Shell
wp queuety retry 42
wp queuety retry-buried

Timeout

Queuety ativa um pcntl_alarm() pelo tempo máximo de execução e deve fazer a tentativa falhar com um TimeoutException quando esse limite for excedido. Esse tempo limite não está sendo aplicado no momento (#10): o worker não habilita sinais assíncronos, portanto, um manipulador de longa duração executa até o fim, enquanto um manipulador bloqueado em sleep() é interrompido quando o alarme dispara e, em seguida, marcado como concluído. Configure o tempo limite globalmente:

PHP
define( 'QUEUETY_MAX_EXECUTION_TIME', 300 ); // 5 minutes

Tarefas que permanecem no status processing por mais de QUEUETY_STALE_TIMEOUT segundos são recuperadas automaticamente:

PHP
define( 'QUEUETY_STALE_TIMEOUT', 600 ); // 10 minutes

Recupere tarefas obsoletas manualmente:

Shell
wp queuety recover

Filas

As tarefas são despachadas para filas nomeadas. Cada worker processa uma fila ou uma lista ordenada de filas (veja Workers):

PHP
Queuety::dispatch( 'handler', $payload )->on_queue( 'emails' );
Shell
wp queuety work --queue=emails

A fila padrão é default. Você pode executar processos de worker separados para cada fila e isolar as cargas de trabalho.

Limitação de taxa

Limite a frequência com que um manipulador pode ser executado dentro de um intervalo de tempo:

PHP
Queuety::dispatch( 'call_api', $payload )
    ->rate_limit( 10, 60 ); // max 10 executions per 60 seconds

Veja Limitação de taxa para obter detalhes.

Classes de tarefas despacháveis

Queuety v0.6.0 introduz uma API de tarefa baseada em classes. Em vez de separar o nome do manipulador, a carga útil e a classe do manipulador, você define uma única classe que encapsula tudo: a carga útil (como propriedades públicas tipadas), a lógica de execução e o middleware opcional.

A interface Contracts\Job

PHP
use Queuety\Contracts\Job;

interface Job {
    public function handle(): void;
}

Uma classe Job armazena sua carga útil como propriedades públicas e executa sua própria lógica em handle(). Não é necessário um método config() separado nem registrar um manipulador.

A trait Dispatchable

Adicione a trait Dispatchable para obter um método estático dispatch() na classe da tarefa:

PHP
use Queuety\Contracts\Job;
use Queuety\Dispatchable;

class SendEmailJob implements Job {
    use Dispatchable;

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

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

Despache-a passando os argumentos do construtor:

PHP
SendEmailJob::dispatch( 'user@example.com', 'Welcome!', 'Hello there.' )
    ->on_queue( 'emails' )
    ->with_priority( Priority::High );

A trait Dispatchable chama internamente Queuety::dispatch(), portanto, todas as opções de PendingJob (fila, prioridade, atraso, max_attempts, unique, after) funcionam exatamente da mesma forma.

Como funciona a serialização

Ao despachar uma instância de Job, o método JobSerializer de Queuety extrai o nome totalmente qualificado da classe como manipulador e todas as propriedades públicas como carga útil. No worker, o serializador reconstrói a instância associando as chaves da carga útil aos nomes dos parâmetros do construtor. Enums com valor de suporte são serializados como o valor subjacente e restaurados automaticamente.

Propriedades do trabalho

As classes de tarefas podem declarar propriedades públicas para controlar o comportamento de novas tentativas e do tempo limite. O worker as lê por reflexão e as aplica automaticamente.

PHP
use Queuety\Contracts\Job;
use Queuety\Dispatchable;

class ImportProductsJob implements Job {
    use Dispatchable;

    public int $tries = 5;
    public int $timeout = 120;
    public array $backoff = [ 10, 30, 60, 120 ];
    public string $concurrency_group = 'imports';
    public int $concurrency_limit = 2;
    public int $cost_units = 4;

    public function __construct(
        public readonly int $supplier_id,
    ) {}

    public function handle(): void {
        // Import products...
    }
}
Propriedade Tipo Descrição
$tries int Número máximo de tentativas antes de a tarefa ser arquivada. Substitui o valor de max_attempts definido no despacho.
$timeout int Tempo máximo de execução em segundos. Substitui a constante global QUEUETY_MAX_EXECUTION_TIME. Requer pcntl e ainda não é aplicada (veja Tempo limite).
$backoff array Valores de atraso em segundos para cada tentativa. O último valor é reutilizado nas tentativas seguintes.
$concurrency_group string Grupo compartilhado de admissão de workers para tarefas caras.
$concurrency_limit int Número máximo de tarefas processing simultâneas nesse grupo. Ignorado sem $concurrency_group.
$cost_units int Custo relativo de execução usado pelos orçamentos de fluxo de trabalho e pela admissão de workers.

O array $backoff fornece atrasos progressivamente maiores entre tentativas. Por exemplo, [10, 30, 60, 120] significa que a primeira nova tentativa aguarda 10 segundos, a segunda aguarda 30 segundos, a terceira aguarda 60 segundos e as tentativas seguintes aguardam 120 segundos.

As propriedades relacionadas a recursos são úteis quando as classes de tarefas representam diferentes perfis de custo. Uma atualização rápida de cache e uma chamada grande a um provedor podem ser, ambas, "uma tarefa", mas não devem necessariamente ter o mesmo peso quando um orçamento de fluxo de trabalho ou uma decisão de admissão de workers tenta manter o processo dentro de limites seguros.

Para ver o modelo completo, incluindo orçamentos de fluxo de trabalho e admissão no worker, consulte Gerenciamento de recursos.

Hook de falha

Quando uma tarefa é arquivada após esgotar todas as tentativas, Queuety chama um método failed() na instância da tarefa, se houver. Use-o para limpeza, alertas ou registros.

PHP
use Queuety\Contracts\Job;
use Queuety\Dispatchable;

class ProcessPaymentJob implements Job {
    use Dispatchable;

    public int $tries = 3;

    public function __construct(
        public readonly int $order_id,
    ) {}

    public function handle(): void {
        // Process the payment...
    }

    public function failed( \Throwable $exception ): void {
        // Notify the team that payment processing failed permanently.
        error_log( "Payment failed for order {$this->order_id}: {$exception->getMessage()}" );
    }
}

O método failed() recebe a exceção que causou a falha final. A instância da tarefa é desserializada com a carga útil original, portanto, todas as propriedades públicas ficam disponíveis.

Despacho condicional

A trait Dispatchable fornece dispatch_if() e dispatch_unless() para despacho condicional. Ambos aceitam uma condição booleana como primeiro argumento, seguida pelos argumentos do construtor da tarefa.

PHP
// Only dispatch if the user has opted in to notifications.
SendEmailJob::dispatch_if( $user->wants_notifications, $user->email, 'Update', $body );

// Dispatch unless the feature flag is disabled.
SyncInventoryJob::dispatch_unless( $maintenance_mode, $sku );

dispatch_if() despacha quando a condição é true e retorna PendingJob. Retorna null quando a condição é false.

dispatch_unless() despacha quando a condição é false e retorna PendingJob. Retorna null quando a condição é true.

Ambos os métodos permitem encadear opções de PendingJob no momento do despacho:

PHP
SendEmailJob::dispatch_if( $should_send, $to, $subject, $body )
    ?->on_queue( 'emails' )
    ?->with_priority( Priority::High );

Despacho síncrono

Use Queuety::dispatch_sync() para executar uma tarefa imediatamente no processo atual, sem adicioná-la à fila. Isso é útil para testes e para tarefas que precisam ser executadas em linha.

PHP
use Queuety\Queuety;

// With a Job instance
Queuety::dispatch_sync( new SendEmailJob( to: 'user@example.com', subject: 'Hello', body: 'Hi!' ) );

// With a handler name and payload
Queuety::dispatch_sync( 'send_email', [ 'to' => 'user@example.com' ] );

O método handle() da tarefa é chamado diretamente. Nenhuma linha é criada no banco de dados, nenhum worker é envolvido e o middleware não é aplicado.

Encadeamento de tarefas

O encadeamento de tarefas executa uma sequência, uma após a outra. Cada tarefa da cadeia depende da conclusão bem-sucedida da anterior. Se alguma tarefa falhar, as tarefas seguintes permanecem pendentes.

Usando Queuety::chain()

PHP
use Queuety\Queuety;

$first_job_id = Queuety::chain( [
    new FetchDataJob( $url ),
    new ProcessDataJob(),
    new NotifyCompleteJob(),
] )
    ->on_queue( 'pipeline' )
    ->catch( ChainFailedHandler::class )
    ->dispatch();

Queuety::chain() retorna um ChainBuilder com métodos encadeáveis para definir a fila e um manipulador de falhas. O método dispatch() cria todas as tarefas com relações depends_on sequenciais e retorna o ID da primeira tarefa.

Usando with_chain()

A trait Dispatchable fornece um método with_chain(). No momento, ele equivale a Queuety::chain( $jobs ): a classe em que é chamado não é adicionada à cadeia (#13), portanto, inclua também na lista a primeira tarefa do array:

PHP
FetchDataJob::with_chain( [
    new FetchDataJob(),
    new ProcessDataJob(),
    new NotifyCompleteJob(),
] )
    ->on_queue( 'pipeline' )
    ->dispatch();

Tratamento de falhas na cadeia

Registre uma classe de manipulador de falhas usando catch(). A classe do manipulador deve ter um método handle(). Ele é chamado quando qualquer tarefa da cadeia é arquivada permanentemente. O worker oferece suporte a handle(), handle( Job $job ) e handle( Job $job, \Throwable $exception ).

PHP
class ChainFailedHandler {
    public function handle(): void {
        // Alert, clean up, etc.
    }
}

Adicionando middleware

As classes de tarefas podem definir um método middleware() para retornar middleware que envolve a execução:

PHP
use Queuety\Contracts\Job;
use Queuety\Dispatchable;
use Queuety\Middleware\RateLimited;
use Queuety\Middleware\Timeout;

class CallOpenAIJob implements Job {
    use Dispatchable;

    public function __construct(
        public readonly string $prompt,
    ) {}

    public function handle(): void {
        // Call the API...
    }

    public function middleware(): array {
        return [
            new RateLimited( max: 60, window: 60 ),
            new Timeout( seconds: 120 ),
        ];
    }
}

Veja Middleware para obter detalhes sobre o middleware integrado e como criar middleware personalizado.

Comparação com tarefas baseadas em manipuladores

Baseado em handlers (v0.1+) Baseado em classes (v0.6+)
Despacho Queuety::dispatch( 'send_email', $payload ) SendEmailJob::dispatch( $to, $subject )
Handler Classe separada que implementa Handler A mesma classe implementa Contracts\Job
Payload array $payload sem tipagem Propriedades públicas tipadas
Registro Queuety::register() ou #[QueuetyHandler] Não é necessário (usa FQCN)
Middleware Não disponível Método middleware() opcional
Configuração Método config() Propriedades do job + cadeia de PendingJob

As duas abordagens têm suporte completo. Os jobs existentes baseados em handlers continuam funcionando sem alterações. Você pode misturar os dois estilos no mesmo projeto.

Ciclo de vida dos jobs

Código
dispatch() -> pending -> processing -> completed
                  |           |
                  |           +-> exception -> pending (retry after backoff)
                  |                       |
                  |                       +-> buried (max attempts reached)
                  |
                  +-> delayed (available_at in the future)
Status Descrição
pending Aguardando para ser reivindicado por um worker
processing Em execução no momento
completed Concluído com sucesso
failed Reservado; o worker não o define atualmente. Uma tentativa com falha que será repetida volta para pending
buried Todas as tentativas de repetição foram esgotadas