- Introduzione
- Definizione dei programmi
- Comandi Artisan di programmazione
- Programmazione dei lavori in coda
- Comandi Shell di programmazione
- Opzioni di frequenza di programmazione
- Timezones
- Evitare sovrapposizioni di compiti
- Eseguire i compiti su un server
- Task in background
- Modalità manutenzione
- Eseguire lo Scheduler
- Eseguire lo Scheduler localmente
- Uscita dei compiti
- Ganci per i compiti
- Introduzione
- Definizione degli scheduler
- Scheduling Artisan Commands
- Scheduling Queued Jobs
- Comandi Shell di programmazione
- Opzioni di frequenza di programmazione
- Costrizioni di giorno
- Between Time Constraints
- Truth Test Constraints
- Costrizioni d’ambiente
- Timezones
- Evitare la sovrapposizione dei compiti
- Esecuzione dei compiti su un server
- Task in background
- Modalità manutenzione
- Running The Scheduler
- Eseguire lo scheduler localmente
- Task Output
- Ganci per task
- Ping degli URL
Introduzione
In passato, potresti aver scritto una voce di configurazione cron per ogni compito che avevi bisogno di programmare sul tuo server. Tuttavia, questo può diventare rapidamente una seccatura perché la pianificazione delle attività non è più nel controllo dei sorgenti e devi entrare con SSH nel tuo server per vedere le voci di cron esistenti o aggiungere voci aggiuntive.
Lo schedulatore di comandi di Laravel offre un nuovo approccio alla gestione delle attività programmate sul tuo server. Lo scheduler ti permette di definire in modo fluido ed espressivo la tua pianificazione dei comandi all’interno della tua applicazione Laravel stessa. Quando usi lo scheduler, è necessaria solo una singola voce cron sul tuo server. Il tuo programma di attività è definito nel metodo schedule
del file app/Console/Kernel.php
. Per aiutarti a iniziare, un semplice esempio è definito all’interno del metodo.
Definizione degli scheduler
Puoi definire tutti i tuoi compiti programmati nel metodo schedule
della classe App\Console\Kernel
della tua applicazione. Per iniziare, diamo un’occhiata ad un esempio. In questo esempio, programmeremo una chiusura da chiamare ogni giorno a mezzanotte. All’interno della chiusura eseguiremo una query al database per cancellare una tabella:
<?phpnamespace App\Console;use Illuminate\Console\Scheduling\Schedule;use Illuminate\Foundation\Console\Kernel as ConsoleKernel;use Illuminate\Support\Facades\DB;class Kernel extends ConsoleKernel{ /** * The Artisan commands provided by your application. * * @var array */ protected $commands = ; /** * Define the application's command schedule. * * @param \Illuminate\Console\Scheduling\Schedule $schedule * @return void */ protected function schedule(Schedule $schedule) { $schedule->call(function () { DB::table('recent_users')->delete(); })->daily(); }}
Oltre a programmare usando le chiusure, puoi anche programmare oggetti invocabili. Gli oggetti invocabili sono semplici classi PHP che contengono un metodo __invoke
:
$schedule->call(new DeleteRecentUsers)->daily();
Se vuoi visualizzare una panoramica delle tue attività pianificate e la prossima volta che devono essere eseguite, puoi usare il comando schedule:list
Artisan:
php artisan schedule:list
Scheduling Artisan Commands
Oltre a programmare le chiusure, puoi anche programmare i comandi Artisan e i comandi di sistema. Per esempio, puoi usare il metodo command
per pianificare un comando Artisan usando sia il nome del comando che la classe.
Quando pianifichi i comandi Artisan usando il nome della classe del comando, puoi passare un array di argomenti addizionali della linea di comando che dovrebbero essere forniti al comando quando viene invocato:
use App\Console\Commands\SendEmailsCommand;$schedule->command('emails:send Taylor --force')->daily();$schedule->command(SendEmailsCommand::class, )->daily();
Scheduling Queued Jobs
Il metodo job
può essere usato per pianificare un lavoro in coda. Questo metodo fornisce un modo conveniente per programmare lavori in coda senza usare il metodo call
per definire le chiusure per accodare il lavoro:
use App\Jobs\Heartbeat;$schedule->job(new Heartbeat)->everyFiveMinutes();
I secondi e terzi argomenti opzionali possono essere forniti al metodo job
che specifica il nome della coda e la connessione della coda che dovrebbe essere usata per accodare il lavoro:
use App\Jobs\Heartbeat;// Dispatch the job to the "heartbeats" queue on the "sqs" connection...$schedule->job(new Heartbeat, 'heartbeats', 'sqs')->everyFiveMinutes();
Comandi Shell di programmazione
Il metodo exec
può essere usato per inviare un comando al sistema operativo:
$schedule->exec('node /home/forge/script.js')->daily();
Opzioni di frequenza di programmazione
Abbiamo già visto alcuni esempi di come si può configurare un compito da eseguire a intervalli specifici. Tuttavia, ci sono molte altre frequenze di pianificazione che puoi assegnare a un’attività:
Metodo | Descrizione |
---|---|
->cron('* * * * *'); |
Esegui il compito su una pianificazione cron personalizzata |
->everyMinute(); |
Esegui il compito ogni minuto |
->everyTwoMinutes(); |
Esegui il compito ogni due minuti |
->everyThreeMinutes(); |
Esegui il compito ogni tre minuti |
->everyFourMinutes(); |
Esegui il compito ogni quattro minuti |
->everyFiveMinutes(); |
Esegui il compito ogni cinque minuti |
->everyTenMinutes(); |
Esegui il compito ogni dieci minuti |
->everyFifteenMinutes(); |
Esegui il compito ogni quindici minuti |
->everyThirtyMinutes(); |
Esegui il compito ogni trenta minuti |
->hourly(); |
Esegui il compito ogni ora |
->hourlyAt(17); |
Esegui il compito ogni ora a 17 minuti dopo l’ora |
->everyTwoHours(); |
Esegui il compito ogni due ore |
->everyThreeHours(); |
Esegui il compito ogni tre ore |
->everyFourHours(); |
Esegui il compito ogni quattro ore |
->everySixHours(); |
Esegui il compito ogni sei ore |
->daily(); |
Esegui il compito ogni giorno a mezzanotte |
->dailyAt('13:00'); |
Esegui il compito ogni giorno alle 13:00 |
->twiceDaily(1, 13); |
Esegui il compito ogni giorno alle 1:00 & 13:00 |
->weekly(); |
Esegui il compito ogni domenica alle 00:00 |
->weeklyOn(1, '8:00'); |
Esegui il compito ogni settimana il lunedì alle 8:00 |
->monthly(); |
Esegui il compito il primo giorno di ogni mese alle 00:00 |
->monthlyOn(4, '15:00'); |
Esegui il compito ogni mese il 4 alle 15:00 |
->twiceMonthly(1, 16, '13:00'); |
Esegui il compito mensilmente il 1 e il 16 alle 13:00 |
->lastDayOfMonth('15:00'); |
Esegui il compito l’ultimo giorno del mese alle 15:00 |
->quarterly(); |
Esegui il task il primo giorno di ogni trimestre alle 00:00 |
->yearly(); |
Esegui il compito il primo giorno di ogni anno alle 00:00 |
->yearlyOn(6, 1, '17:00'); |
Esegui il compito ogni anno il primo giugno alle 17:00 |
->timezone('America/New_York'); |
Imposta il fuso orario per il compito |
Questi metodi possono essere combinati con vincoli aggiuntivi per creare pianificazioni ancora più precise che vengono eseguite solo in certi giorni della settimana. Per esempio, puoi programmare un comando da eseguire settimanalmente il lunedì:
// Run once per week on Monday at 1 PM...$schedule->call(function () { //})->weekly()->mondays()->at('13:00');// Run hourly from 8 AM to 5 PM on weekdays...$schedule->command('foo') ->weekdays() ->hourly() ->timezone('America/Chicago') ->between('8:00', '17:00');
Un elenco di vincoli di pianificazione aggiuntivi può essere trovato qui sotto:
Metodo | Descrizione |
---|---|
->weekdays(); |
Limitare il compito ai giorni della settimana |
->weekends(); |
Limita il compito ai fine settimana |
->sundays(); |
Limita il compito alla domenica |
->mondays(); |
Limita il compito a lunedì |
->tuesdays(); |
Limita il compito a martedì |
->wednesdays(); |
Limita il compito a mercoledì |
->thursdays(); |
Limita il compito a giovedì |
->fridays(); |
Limita il compito a venerdì |
->saturdays(); |
Limita il compito al sabato |
->days(array|mixed); |
Limita il compito a giorni specifici |
->between($startTime, $endTime); |
Limitare l’esecuzione del compito tra le ore di inizio e fine |
->unlessBetween($startTime, $endTime); |
Limitare l’esecuzione del compito tra le ore di inizio e fine |
->when(Closure); |
Limitare il compito basato su un test di verità |
->environments($env); |
Limitare il compito a specifici ambienti |
Costrizioni di giorno
Il metodo days
può essere usato per limitare l’esecuzione di un compito a specifici giorni della settimana. Per esempio, puoi programmare un comando da eseguire ogni ora la domenica e il mercoledì:
$schedule->command('emails:send') ->hourly() ->days();
In alternativa, puoi usare le costanti disponibili sulla classe Illuminate\Console\Scheduling\Schedule
quando definisci i giorni in cui un compito dovrebbe essere eseguito:
use Illuminate\Console\Scheduling\Schedule;$schedule->command('emails:send') ->hourly() ->days();
Between Time Constraints
Il metodo between
può essere usato per limitare l’esecuzione di un compito in base all’ora del giorno:
$schedule->command('emails:send') ->hourly() ->between('7:00', '22:00');
Similmente, il metodo unlessBetween
può essere usato per escludere l’esecuzione di un compito per un periodo di tempo:
$schedule->command('emails:send') ->hourly() ->unlessBetween('23:00', '4:00');
Truth Test Constraints
Il metodo when
può essere usato per limitare l’esecuzione di un compito basato sul risultato di un dato test di verità. In altre parole, se la chiusura data restituisce true
, il compito verrà eseguito fino a quando nessun’altra condizione vincolante impedirà l’esecuzione del compito:
$schedule->command('emails:send')->daily()->when(function () { return true;});
Il metodo skip
può essere visto come l’inverso di when
. Se il metodo skip
restituisce true
, il compito programmato non verrà eseguito:
$schedule->command('emails:send')->daily()->skip(function () { return true;});
Quando si usano metodi when
concatenati, il comando programmato verrà eseguito solo se tutte le condizioni when
restituiscono true
.
Costrizioni d’ambiente
Il metodo environments
può essere usato per eseguire i compiti solo su determinati ambienti (come definito dalla variabile d’ambiente APP_ENV
):
$schedule->command('emails:send') ->daily() ->environments();
Timezones
Utilizzando il metodo timezone
, puoi specificare che l’orario di un compito programmato deve essere interpretato all’interno di un dato fuso orario:
$schedule->command('report:generate') ->timezone('America/New_York') ->at('2:00')
Se assegni ripetutamente lo stesso fuso orario a tutti i tuoi compiti programmati, potresti voler definire un metodo scheduleTimezone
nella tua classe App\Console\Kernel
. Questo metodo dovrebbe restituire il fuso orario predefinito che dovrebbe essere assegnato a tutte le attività programmate:
/** * Get the timezone that should be used by default for scheduled events. * * @return \DateTimeZone|string|null */protected function scheduleTimezone(){ return 'America/Chicago';}
{note} Ricorda che alcuni fusi orari utilizzano l’ora legale. Quando cambia l’ora legale, il tuo compito programmato potrebbe essere eseguito due volte o addirittura non essere eseguito affatto. Per questa ragione, raccomandiamo di evitare la programmazione per fusi orari quando possibile.
Evitare la sovrapposizione dei compiti
Per impostazione predefinita, i compiti programmati saranno eseguiti anche se l’istanza precedente del compito è ancora in esecuzione. Per evitare questo, puoi usare il metodo withoutOverlapping
:
$schedule->command('emails:send')->withoutOverlapping();
In questo esempio, il comando emails:send
Artisan sarà eseguito ogni minuto se non è già in esecuzione. Il metodo withoutOverlapping
è particolarmente utile se avete compiti che variano drasticamente nel loro tempo di esecuzione, impedendovi di prevedere esattamente quanto tempo un dato compito richiederà.
Se necessario, potete specificare quanti minuti devono passare prima che il blocco “senza sovrapposizione” scada. Per impostazione predefinita, il blocco scade dopo 24 ore:
$schedule->command('emails:send')->withoutOverlapping(10);
Esecuzione dei compiti su un server
{note} Per utilizzare questa caratteristica, la tua applicazione deve utilizzare il driver cache
database
,memcached
,dynamodb
oredis
come driver cache predefinito della tua applicazione. Inoltre, tutti i server devono comunicare con lo stesso server di cache centrale.
Se lo scheduler della tua applicazione è in esecuzione su più server, puoi limitare un lavoro pianificato per eseguirlo solo su un singolo server. Per esempio, supponiamo che abbiate un’attività pianificata che genera un nuovo rapporto ogni venerdì sera. Se il task scheduler è in esecuzione su tre server worker, il task pianificato verrà eseguito su tutti e tre i server e genererà il report tre volte. Non va bene!
Per indicare che il compito deve essere eseguito solo su un server, usa il metodo onOneServer
quando definisci il compito programmato. Il primo server che otterrà il compito si assicurerà un blocco atomico sul lavoro per evitare che altri server eseguano lo stesso compito allo stesso tempo:
$schedule->command('report:generate') ->fridays() ->at('17:00') ->onOneServer();
Task in background
Per impostazione predefinita, più compiti programmati allo stesso tempo verranno eseguiti in sequenza in base all’ordine in cui sono definiti nel tuo metodo schedule
. Se hai compiti di lunga durata, questo può causare che i compiti successivi inizino molto più tardi del previsto. Se vuoi eseguire i compiti in background in modo che possano essere eseguiti tutti simultaneamente, puoi usare il metodo runInBackground
:
$schedule->command('analytics:report') ->daily() ->runInBackground();
{note} Il metodo
runInBackground
può essere usato solo quando si programmano i compiti tramite i metodicommand
eexec
.
Modalità manutenzione
I compiti programmati della tua applicazione non verranno eseguiti quando l’applicazione è in modalità manutenzione, poiché non vogliamo che i tuoi compiti interferiscano con qualsiasi manutenzione non terminata che potresti eseguire sul tuo server. Tuttavia, se vuoi forzare l’esecuzione di un’attività anche in modalità di manutenzione, puoi chiamare il metodo evenInMaintenanceMode
quando definisci l’attività:
$schedule->command('emails:send')->evenInMaintenanceMode();
Running The Scheduler
Ora che abbiamo imparato come definire le attività pianificate, parliamo di come eseguirle effettivamente sul nostro server. Il comando schedule:run
Artisan valuterà tutti i tuoi compiti programmati e determinerà se devono essere eseguiti in base all’ora corrente del server.
Quindi, quando usiamo lo scheduler di Laravel, abbiamo solo bisogno di aggiungere una singola voce di configurazione cron al nostro server che esegua il comando schedule:run
ogni minuto. Se non sai come aggiungere voci di cron al tuo server, considera di usare un servizio come Laravel Forge che può gestire le voci di cron per te:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
Eseguire lo scheduler localmente
In genere, non dovresti aggiungere una voce di cron dello scheduler alla tua macchina di sviluppo locale. Invece, puoi usare il comando schedule:work
Artisan. Questo comando verrà eseguito in primo piano e invocherà lo scheduler ogni minuto fino a quando non terminerai il comando:
php artisan schedule:work
Task Output
Lo scheduler Laravel fornisce diversi metodi convenienti per lavorare con l’output generato dai task programmati. Per prima cosa, usando il metodo sendOutputTo
, puoi inviare l’output a un file per un controllo successivo:
$schedule->command('emails:send') ->daily() ->sendOutputTo($filePath);
Se vuoi aggiungere l’output a un dato file, puoi usare il metodo appendOutputTo
:
$schedule->command('emails:send') ->daily() ->appendOutputTo($filePath);
Utilizzando il metodo emailOutputTo
, puoi inviare l’output a un indirizzo email di tua scelta. Prima di inviare l’output di un task via email, dovresti configurare i servizi email di Laravel:
$schedule->command('report:generate') ->daily() ->sendOutputTo($filePath) ->emailOutputTo('');
Se vuoi inviare l’output via email solo se il comando Artisan o di sistema programmato termina con un codice di uscita diverso da zero, usa il metodo emailOutputOnFailure
:
$schedule->command('report:generate') ->daily() ->emailOutputOnFailure('');
{note} I metodi
emailOutputTo
,emailOutputOnFailure
,sendOutputTo
eappendOutputTo
sono esclusivi dei metodicommand
eexec
.
Ganci per task
Utilizzando i metodi before
e after
, è possibile specificare il codice da eseguire prima e dopo l’esecuzione del task programmato:
$schedule->command('emails:send') ->daily() ->before(function () { // The task is about to execute... }) ->after(function () { // The task has executed... });
I metodi onSuccess
e onFailure
permettono di specificare il codice da eseguire se il task programmato ha successo o fallisce. Un fallimento indica che il comando programmato di Artisan o di sistema è terminato con un codice di uscita diverso da zero:
$schedule->command('emails:send') ->daily() ->onSuccess(function () { // The task succeeded... }) ->onFailure(function () { // The task failed... });
Se l’output è disponibile dal vostro comando, potete accedervi nei vostri after
, onSuccess
o onFailure
hooks indicando un’istanza Illuminate\Support\Stringable
come argomento $output
della definizione della chiusura del vostro hook:
use Illuminate\Support\Stringable;$schedule->command('emails:send') ->daily() ->onSuccess(function (Stringable $output) { // The task succeeded... }) ->onFailure(function (Stringable $output) { // The task failed... });
Ping degli URL
Utilizzando i metodi pingBefore
e thenPing
, lo scheduler può eseguire automaticamente il ping di un dato URL prima o dopo l’esecuzione di un compito. Questo metodo è utile per notificare un servizio esterno, come Envoyer, che il tuo compito programmato sta iniziando o ha finito l’esecuzione:
$schedule->command('emails:send') ->daily() ->pingBefore($url) ->thenPing($url);
I metodi pingBeforeIf
e thenPingIf
possono essere usati per eseguire il ping di un dato URL solo se una data condizione è true
:
$schedule->command('emails:send') ->daily() ->pingBeforeIf($condition, $url) ->thenPingIf($condition, $url);
I metodi pingOnSuccess
e pingOnFailure
possono essere usati per eseguire il ping di un dato URL solo se il compito ha successo o fallisce. Un fallimento indica che il comando Artisan o di sistema programmato è terminato con un codice di uscita non zero:
$schedule->command('emails:send') ->daily() ->pingOnSuccess($successUrl) ->pingOnFailure($failureUrl);
Tutti i metodi di ping richiedono la libreria Guzzle HTTP. Guzzle è tipicamente installato in tutti i nuovi progetti Laravel per impostazione predefinita, ma, puoi installare manualmente Guzzle nel tuo progetto usando il gestore di pacchetti Composer se è stato accidentalmente rimosso:
composer require guzzlehttp/guzzle
Lascia un commento