Saltar al contenido

Jobs

Las tareas son la unidad básica de trabajo en Queuety. Envíe una tarea con el nombre de un controlador y una carga útil; un worker la recoge y la ejecuta en segundo plano.

Envío de tareas

PHP
use Queuety\Queuety;

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

dispatch() devuelve un generador PendingJob. Puede encadenar opciones antes de que se envíe automáticamente:

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 obtener el ID de la tarea de inmediato, llame a ->id():

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

Escritura de controladores

Un controlador puede ser cualquier clase que implemente la interfaz 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',
        ];
    }
}

El método handle() recibe la carga útil de la tarea y ejecuta el trabajo. El método config() devuelve valores predeterminados opcionales:

Clave Tipo Descripción
queue string Nombre predeterminado de la cola
max_attempts int Número máximo de ejecuciones, incluida la primera, antes de que se archive la tarea
backoff string Estrategia de espera entre reintentos: exponential, linear o fixed
rate_limit array Límite de frecuencia como [max_executions, window_seconds]
concurrency_group string Grupo compartido de admisión de workers para controladores costosos
concurrency_limit int Máximo de tareas en procesamiento simultáneo dentro del grupo
cost_units int Coste de ejecución relativo que se usa en colas ponderadas, presupuestos de proveedores y flujos de trabajo, y heurísticas de admisión

Estas claves de recursos forman parte del modelo más amplio de Resource Management de Queuety, donde los metadatos de las tareas, los presupuestos de flujos de trabajo y la admisión de workers funcionan en conjunto.

Registre el controlador:

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

O use los atributos PHP para el registro automático.

Prioridad

Los trabajos tienen cuatro niveles de prioridad. Los trabajadores reclaman primero los trabajos de mayor prioridad.

PHP
use Queuety\Enums\Priority;

Queuety::dispatch( 'handler', $payload )->with_priority( Priority::Urgent );
Nivel Valor Descripción
Priority::Low 0 Predeterminada. Trabajo en segundo plano que puede esperar.
Priority::Normal 1 Prioridad estándar.
Priority::High 2 Se procesa antes que los de prioridad baja y normal.
Priority::Urgent 3 Se procesa primero. Úsela con moderación.

Retraso

Retrase un trabajo para que esté disponible solo después del número de segundos especificado:

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

El trabajo se inserta de inmediato, pero los trabajadores no lo reclamarán hasta que haya transcurrido el retraso.

Trabajos únicos

Evite los envíos duplicados para el mismo controlador y la misma carga útil. Si ya existe un trabajo pendiente o en curso con el mismo controlador y la misma carga útil, se devuelve el ID del trabajo existente en lugar de crear uno nuevo.

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

Dependencias entre trabajos

Un trabajo puede depender de otro. Un trabajador no lo reclamará hasta que se haya completado la dependencia.

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

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

Envío por lotes

Envíe varios trabajos en una sola instrucción INSERT de varias filas para obtener el máximo rendimiento:

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 elemento puede incluir claves opcionales: queue, priority, delay, max_attempts.

Reintentos y espera progresiva

Cuando un trabajo lanza una excepción, Queuety lo devuelve a pending con un available_at retrasado hasta que se haya ejecutado max_attempts veces en total (cuenta también la primera ejecución, por lo que max_attempts( 3 ) permite hasta dos reintentos). La estrategia de espera progresiva determina el retraso antes de cada reintento, donde attempt es el número de la ejecución que acaba de fallar:

Estrategia Fórmula del retraso Ejemplo (tras las ejecuciones 1, 2 y 3)
exponential 2^attempt * 30 segundos, con un máximo de 3600 60s, 120s, 240s
linear attempt * 60 segundos 60s, 120s, 180s
fixed 60 segundos 60s, 60s, 60s

Establezca el valor predeterminado global en wp-config.php:

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

O por controlador en config():

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

O por envío:

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

Trabajos en la cola de fallidos

Tras agotar todos los intentos de reintento, un trabajo se marca como enterrado. Los trabajos enterrados permanecen en la base de datos para su inspección, pero no se procesan. Puede reintentarlos manualmente. Un reintento manual vuelve a poner el trabajo en pending sin restablecer el recuento de intentos; así, un trabajo enterrado que se reintenta se ejecuta una vez más y vuelve a quedar enterrado si esa ejecución falla:

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

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

O mediante CLI:

Shell
wp queuety retry 42
wp queuety retry-buried

Tiempo de espera

Queuety activa una pcntl_alarm() para el tiempo máximo de ejecución y está pensado para hacer fallar el intento con un TimeoutException cuando se supera ese límite. Actualmente, ese tiempo de espera no se aplica (#10): el trabajador no habilita las señales asíncronas, por lo que un controlador de larga duración se ejecuta hasta el final, mientras que un controlador bloqueado en sleep() se interrumpe cuando suena la alarma y luego se marca como completado. Configure el tiempo de espera globalmente:

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

Los trabajos que permanecen en estado processing durante más de QUEUETY_STALE_TIMEOUT segundos se recuperan automáticamente:

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

Recupere manualmente los trabajos obsoletos:

Shell
wp queuety recover

Colas

Los trabajos se envían a colas con nombre. Cada trabajador procesa una cola o una lista ordenada de colas (consulte Trabajadores):

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

La cola predeterminada es default. Puede ejecutar procesos de trabajador independientes para cada cola y así aislar las cargas de trabajo.

Limitación de frecuencia

Limite la frecuencia con la que puede ejecutarse un controlador dentro de un intervalo de tiempo:

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

Consulte Limitación de frecuencia para obtener más detalles.

Clases de trabajo enviables

Queuety v0.6.0 incorpora un trabajo basado en clases API. En lugar de separar el nombre del controlador, la carga útil y la clase del controlador, se define una sola clase que lo encapsula todo: la carga útil (como propiedades públicas tipadas), la lógica de ejecución y el middleware opcional.

La interfaz Contracts\Job

PHP
use Queuety\Contracts\Job;

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

Una clase Job almacena su carga útil en propiedades públicas y ejecuta su propia lógica en handle(). No se requiere un método config() ni registrar un controlador por separado.

El rasgo Dispatchable

Añada el rasgo Dispatchable para obtener un método estático dispatch() en su clase de trabajo:

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 );
    }
}

Envíelo pasando los argumentos del constructor:

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

El rasgo Dispatchable llama internamente a Queuety::dispatch(), por lo que todas las opciones de PendingJob (cola, prioridad, retraso, max_attempts, unique, after) funcionan exactamente igual.

Cómo funciona la serialización

Al enviar una instancia de Job, el Queuety de JobSerializer extrae el nombre completo de la clase como controlador y todas las propiedades públicas como carga útil. En el lado del trabajador, el serializador reconstruye la instancia haciendo coincidir las claves de la carga útil con los nombres de los parámetros del constructor. Los enumerados con valor asociado se serializan con su valor subyacente y se restauran automáticamente.

Propiedades de las tareas

Las clases de trabajo pueden declarar propiedades públicas para controlar los reintentos y el tiempo de espera. El trabajador las lee mediante reflexión y las aplica automáticamente.

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...
    }
}
Propiedad Tipo Descripción
$tries int Número máximo de intentos antes de que el trabajo quede enterrado. Sobrescribe el valor max_attempts definido al enviar.
$timeout int Tiempo máximo de ejecución en segundos. Sobrescribe la constante global QUEUETY_MAX_EXECUTION_TIME. Requiere pcntl y aún no se aplica (consulte Tiempo de espera).
$backoff array Matriz de valores de retraso en segundos para cada intento de reintento. El último valor se reutiliza en los intentos posteriores.
$concurrency_group string Grupo compartido de admisión de trabajadores para trabajos costosos.
$concurrency_limit int Número máximo de trabajos processing simultáneos en ese grupo. Se ignora si no se configura $concurrency_group.
$cost_units int Coste de ejecución relativo que usan los presupuestos del flujo de trabajo y la admisión de trabajadores.

La matriz $backoff proporciona retrasos de reintento progresivos. Por ejemplo, [10, 30, 60, 120] significa que el primer reintento espera 10 segundos, el segundo 30 segundos, el tercero 60 segundos y los siguientes, 120 segundos.

Las propiedades relacionadas con los recursos son útiles cuando las clases de trabajo representan distintos perfiles de coste. Una actualización rápida de la caché y una llamada extensa a un proveedor pueden ser «un trabajo» cada una, pero no deberían contabilizarse necesariamente igual cuando un presupuesto de flujo de trabajo o una decisión de admisión de trabajadores intenta mantener el proceso dentro de unos límites seguros.

Consulte Gestión de recursos para conocer el modelo completo, incluidos los presupuestos de flujo de trabajo y la admisión en el lado del trabajador.

Hook de fallo

Cuando un trabajo queda enterrado tras agotar todos los intentos de reintento, Queuety llama a un método failed() en la instancia del trabajo, si está definido. Úselo para tareas de limpieza, alertas o registro.

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()}" );
    }
}

El método failed() recibe la excepción que causó el fallo definitivo. La instancia del trabajo se deserializa con su carga útil original, por lo que están disponibles todas las propiedades públicas.

Envío condicional

El rasgo Dispatchable proporciona dispatch_if() y dispatch_unless() para realizar envíos condicionales. Ambos aceptan una condición booleana como primer argumento, seguida de los argumentos del constructor del trabajo.

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() realiza el envío cuando la condición es true y devuelve PendingJob. Devuelve null cuando la condición es false.

dispatch_unless() realiza el envío cuando la condición es false y devuelve PendingJob. Devuelve null cuando la condición es true.

Ambos métodos admiten opciones PendingJob encadenadas cuando realizan el envío:

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

Envío síncrono

Use Queuety::dispatch_sync() para ejecutar un trabajo de inmediato en el proceso actual, sin añadirlo a la cola. Es útil para hacer pruebas y para trabajos que deben ejecutarse en línea.

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

Se llama directamente al método handle() del trabajo. No se crea ninguna fila en la base de datos, no interviene ningún worker ni se aplica middleware.

Encadenamiento de trabajos

El encadenamiento de trabajos ejecuta una serie de trabajos uno tras otro. Cada trabajo de la cadena depende de que el anterior se complete correctamente. Si algún trabajo falla, los siguientes de la cadena quedan pendientes.

Uso de 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() devuelve un ChainBuilder con métodos encadenables para establecer la cola y un controlador de fallos. El método dispatch() crea todos los trabajos con relaciones depends_on secuenciales y devuelve el ID del primer trabajo.

Uso de with_chain()

El rasgo Dispatchable proporciona un método with_chain(). Actualmente, equivale a Queuety::chain( $jobs ): la clase desde la que se llama no se añade a la cadena (#13), así que incluya también el primer trabajo en la matriz:

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

Gestión de fallos en la cadena

Registre una clase controladora de fallos mediante catch(). La clase controladora debe tener un método handle(). Se llama cuando cualquier trabajo de la cadena queda enterrado de forma permanente. El trabajador admite handle(), handle( Job $job ) y handle( Job $job, \Throwable $exception ).

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

Añadir middleware

Las clases de trabajo pueden definir un método middleware() que devuelva middleware para envolver la ejecución:

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

Consulte Middleware para obtener más información sobre el middleware integrado y cómo escribir middleware personalizado.

Comparación con trabajos basados en controladores

Basado en controladores (v0.1+) Basado en clases (v0.6+)
Envío Queuety::dispatch( 'send_email', $payload ) SendEmailJob::dispatch( $to, $subject )
Controlador Clase aparte que implementa Handler La misma clase implementa Contracts\Job
Carga útil array $payload sin tipar Propiedades públicas tipadas
Registro Queuety::register() o #[QueuetyHandler] No es necesario (usa FQCN)
Middleware No disponible Método middleware() opcional
Configuración Método config() Propiedades del trabajo + cadena PendingJob

Ambos enfoques son totalmente compatibles. Los trabajos basados en controladores existentes siguen funcionando sin cambios. Puede combinar ambos estilos en el mismo proyecto.

Ciclo de vida del trabajo

Código
dispatch() -> pending -> processing -> completed
                  |           |
                  |           +-> exception -> pending (retry after backoff)
                  |                       |
                  |                       +-> buried (max attempts reached)
                  |
                  +-> delayed (available_at in the future)
Estado Descripción
pending A la espera de que un trabajador lo reclame
processing En ejecución
completed Finalizado correctamente
failed Reservado; el trabajador no lo establece actualmente. Un intento fallido que se reintentará vuelve a pending
buried Se agotaron todos los intentos de reintento