Gå til indhold

Jobs

Jobs er den grundlæggende arbejdsenhed i Queuety. Send et job med et handlernavn og en payload, hvorefter en worker henter og udfører det i baggrunden.

Afsendelse af jobs

PHP
use Queuety\Queuety;

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

dispatch() returnerer en builder af typen PendingJob. Du kan kæde valgmuligheder på, før den automatisk sender jobbet:

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

Kald ->id() for at få job-id'et med det samme:

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

Skrivning af handlere

En handler er en vilkårlig klasse, der implementerer Queuety\Handler-grænsefladen:

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

Metoden handle() modtager jobpayloaden og udfører arbejdet. Metoden config() returnerer valgfrie standardværdier:

Nøgle Type Beskrivelse
queue string Standardkøens navn
max_attempts int Maksimalt antal kørsler, inklusive den første, før jobbet lægges til side
backoff string Strategi for forsinkelse ved nyt forsøg: exponential, linear eller fixed
rate_limit array Hastighedsgrænse som [max_executions, window_seconds]
concurrency_group string Fælles worker-adgangsgruppe for ressourcekrævende handlere
concurrency_limit int Maksimalt antal samtidige behandlingsjobs i gruppen
cost_units int Relativ afviklingsomkostning brugt af vægtede kø- eller udbyderbudgetter, workflowbudgetter og adgangsheuristikker

Disse ressourcenøgler indgår i Queuetys bredere model for Resource Management, hvor jobmetadata, workflowbudgetter og worker-adgangskontrol fungerer sammen.

Registrér handleren:

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

Eller brug attributterne PHP til automatisk registrering.

Prioritet

Jobs har fire prioritetsniveauer. Workers henter jobs med højere prioritet først.

PHP
use Queuety\Enums\Priority;

Queuety::dispatch( 'handler', $payload )->with_priority( Priority::Urgent );
Niveau Værdi Beskrivelse
Priority::Low 0 Standard. Baggrundsarbejde, der kan vente.
Priority::Normal 1 Normal prioritet.
Priority::High 2 Behandles før Low og Normal.
Priority::Urgent 3 Behandles først. Bruges med omtanke.

Forsinkelse

Forsink et job, så det først bliver tilgængeligt efter det angivne antal sekunder:

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

Jobbet indsættes med det samme, men workers henter det først, når forsinkelsen er udløbet.

Unikke jobs

Undgå gentagne afsendelser med samme handler og payload. Hvis der allerede findes et afventende eller igangværende job med samme handler og payload, returneres det eksisterende job-id i stedet for at oprette et nyt.

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

Jobafhængigheder

Et job kan afhænge af et andet job. En worker henter det først, når afhængigheden er fuldført.

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

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

Afsendelse af batches

Send flere jobs i én INSERT med flere rækker for at opnå maksimal gennemstrømning:

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

Hvert element kan indeholde valgfrie nøgler: queue, priority, delay, max_attempts.

Nye forsøg og forsinkelse

Når et job udløser en undtagelse, flytter Queuety det tilbage til pending med en forsinket available_at, indtil det er kørt max_attempts gange i alt (første kørsel tæller med, så max_attempts( 3 ) betyder op til to nye forsøg). Forsinkelsen før hvert nyt forsøg bestemmes af strategien for forsinkelse, hvor attempt er nummeret på den kørsel, der netop mislykkedes:

Strategi Formel for forsinkelse Eksempel (efter kørsel 1, 2, 3)
exponential 2^attempt * 30 sekunder, højst 3600 60s, 120s, 240s
linear attempt * 60 sekunder 60s, 120s, 180s
fixed 60 sekunder 60s, 60s, 60s

Angiv den globale standard i wp-config.php:

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

Eller pr. handler i config():

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

Eller pr. afsendelse:

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

Parkerede jobs

Når alle forsøg på ny kørsel er brugt, markeres jobbet som lagt til side. Jobs, der er lagt til side, bliver i databasen til gennemsyn, men behandles ikke. Du kan prøve dem igen manuelt. Et manuelt nyt forsøg gør jobbet til pending igen uden at nulstille forsøgsantallet, så et job, der er lagt til side, får én ekstra kørsel og lægges til side igen, hvis den mislykkes:

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

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

Eller via CLI:

Shell
wp queuety retry 42
wp queuety retry-buried

Timeout

Queuety starter en pcntl_alarm() for den maksimale afviklingstid og skal få forsøget til at mislykkes med en TimeoutException, hvis tiden overskrides. Timeouten håndhæves i øjeblikket ikke (#10): workeren aktiverer ikke asynkrone signaler, så en langvarig handler kører færdig, mens en handler, der blokerer i sleep(), afbrydes, når alarmen udløses, og markeres derefter som fuldført. Konfigurér timeouten globalt:

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

Jobs, der sidder fast i status processing i længere tid end QUEUETY_STALE_TIMEOUT sekunder, gendannes automatisk:

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

Gendan forældede jobs manuelt:

Shell
wp queuety recover

Køer

Jobs sendes til navngivne køer. Hver worker behandler én kø eller en sorteret liste over køer (se Workers):

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

Standardkøen er default. Du kan køre separate worker-processer for hver kø for at isolere arbejdsbelastninger.

Hastighedsbegrænsning

Begræns, hvor ofte en handler kan køre inden for et tidsvindue:

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

Se Rate Limiting for flere oplysninger.

Jobklasser, der kan sendes

Queuety v0.6.0 introducerer en klassebaseret job-API. I stedet for at adskille handlernavn, payload og handlerklasse definerer du én klasse, der samler det hele: payloaden (som typede offentlige egenskaber), afviklingslogikken og valgfri middleware.

Grænsefladen Contracts\Job

PHP
use Queuety\Contracts\Job;

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

En Job-klasse gemmer sin payload som offentlige egenskaber og udfører sin egen logik i handle(). Der kræves ingen separat metode config() eller handlerregistrering.

Traitet Dispatchable

Tilføj traitet Dispatchable for at få en statisk metode dispatch() i din jobklasse:

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

Send jobbet ved at angive konstruktørargumenter:

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

Traitet Dispatchable kalder Queuety::dispatch() internt, så alle PendingJob-valgmuligheder (queue, priority, delay, max_attempts, unique, after) fungerer på præcis samme måde.

Sådan fungerer serialisering

Når du sender en instans af Job, udtrækker Queuetys JobSerializer det fuldt kvalificerede klassenavn som handler og alle offentlige egenskaber som payload. På worker-siden genskaber serializeren instansen ved at matche payloadnøgler med konstruktørens parameternavne. Backed enums serialiseres til deres underliggende værdi og gendannes automatisk.

Jobegenskaber

Jobklasser kan erklære offentlige egenskaber, der styrer adfærd ved gentagne forsøg og timeouts. Workeren læser dem med reflection og anvender dem automatisk.

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...
    }
}
Egenskab Type Beskrivelse
$tries int Maksimalt antal forsøg, før jobbet lægges til side. Tilsidesætter værdien max_attempts fra afsendelsen.
$timeout int Maksimal afviklingstid i sekunder. Tilsidesætter den globale konstant QUEUETY_MAX_EXECUTION_TIME. Kræver pcntl og håndhæves endnu ikke (se Timeout).
$backoff array Array med forsinkelsesværdier i sekunder for hvert nyt forsøg. Den sidste værdi genbruges ved efterfølgende forsøg.
$concurrency_group string Fælles worker-adgangsgruppe for ressourcekrævende jobs.
$concurrency_limit int Maksimalt antal samtidige processing-jobs i gruppen. Ignoreres uden $concurrency_group.
$cost_units int Relativ afviklingsomkostning brugt af workflowbudgetter og worker-adgangskontrol.

Arrayet $backoff angiver stigende forsinkelser mellem nye forsøg. For eksempel betyder [10, 30, 60, 120], at det første nye forsøg venter 10 sekunder, det andet 30 sekunder, det tredje 60 sekunder, og at eventuelle efterfølgende forsøg venter 120 sekunder.

Ressourceegenskaberne er nyttige, når jobklasser repræsenterer forskellige omkostningsprofiler. En hurtig cacheopdatering og et stort udbyderkald kan begge være »ét job«, men de bør ikke nødvendigvis tælle ens, når et workflowbudget eller en beslutning om worker-adgang skal holde processen inden for sikre rammer.

Se Resource Management for hele modellen, herunder workflowbudgetter og adgangskontrol på workersiden.

Hook ved fejl

Når et job lægges til side efter at have brugt alle forsøg på ny kørsel, kalder Queuety metoden failed() på jobinstansen, hvis den er defineret. Brug den til oprydning, alarmer eller logning.

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

Metoden failed() modtager den undtagelse, der forårsagede den endelige fejl. Jobinstansen deserialiseres med sin oprindelige payload, så alle offentlige egenskaber er tilgængelige.

Betinget afsendelse

Traitet Dispatchable indeholder dispatch_if() og dispatch_unless() til betinget afsendelse. Begge tager en boolesk betingelse som første argument efterfulgt af jobbets konstruktørargumenter.

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() sender jobbet, når betingelsen er true, og returnerer PendingJob. Den returnerer null, når betingelsen er false.

dispatch_unless() sender jobbet, når betingelsen er false, og returnerer PendingJob. Den returnerer null, når betingelsen er true.

Begge metoder understøtter kædning af PendingJob-valgmuligheder ved afsendelse:

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

Synkron afsendelse

Brug Queuety::dispatch_sync() til at udføre et job straks i den aktuelle proces uden at føje det til køen. Det er nyttigt til test og for jobs, der skal køre direkte.

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

Jobbets metode handle() kaldes direkte. Der oprettes ingen databaserække, ingen worker involveres, og middleware anvendes ikke.

Kædning af jobs

Jobkædning udfører en række jobs efter hinanden. Hvert job i kæden afhænger af, at det foregående job gennemføres korrekt. Hvis et job fejler, forbliver de efterfølgende jobs i kæden afventende.

Brug af 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() returnerer en ChainBuilder med flydende metoder til at angive køen og en fejlhåndtering. Metoden dispatch() opretter alle jobs med sekventielle depends_on-relationer og returnerer ID'et på det første job.

Brug af with_chain()

Trait'et Dispatchable stiller metoden with_chain() til rådighed. Den svarer i øjeblikket til Queuety::chain( $jobs ): Klassen, den kaldes på, føjes ikke til kæden (#13), så angiv også det første job i arrayet:

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

Håndtering af kædefejl

Registrér en klasse til fejlhåndtering med catch(). Handlerklassen skal have en handle()-metode. Den kaldes, når et job i kæden ender permanent i karantæne. Workeren understøtter handle(), handle( Job $job ) og handle( Job $job, \Throwable $exception ).

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

Tilføjelse af middleware

Jobklasser kan definere en middleware()-metode, der returnerer middleware til at omslutte kørslen:

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

Se Middleware for detaljer om indbygget middleware og om at skrive brugerdefineret middleware.

Sammenligning med handlerbaserede jobs

Handlerbaseret (v0.1+) Klassebaseret (v0.6+)
Afsendelse Queuety::dispatch( 'send_email', $payload ) SendEmailJob::dispatch( $to, $subject )
Handler Separat klasse, der implementerer Handler Samme klasse implementerer Contracts\Job
Payload Utypet array $payload Typede offentlige egenskaber
Registrering Queuety::register() eller #[QueuetyHandler] Ikke påkrævet (bruger FQCN)
Middleware Ikke tilgængelig Valgfri middleware()-metode
Konfiguration config()-metode Jobegenskaber + PendingJob-kæde

Begge tilgange understøttes fuldt ud. Eksisterende handlerbaserede jobs fungerer videre uden ændringer. Du kan blande begge stilarter i samme projekt.

Joblivscyklus

Kode
dispatch() -> pending -> processing -> completed
                  |           |
                  |           +-> exception -> pending (retry after backoff)
                  |                       |
                  |                       +-> buried (max attempts reached)
                  |
                  +-> delayed (available_at in the future)
Status Beskrivelse
pending Venter på at blive overtaget af en worker
processing Udføres i øjeblikket
completed Afsluttet korrekt
failed Reserveret; workeren sætter den ikke i dag. Et fejlet forsøg, der skal prøves igen, går tilbage til pending
buried Alle genforsøg er opbrugt