v13.39.0 e applica allo sviluppo di pacchetti le operazioni di base del Task scheduling. Per il caricamento dei provider consultate Struttura interna del package auto-discovery, per la pubblicazione della configurazione Merge e cache della configurazione dei pacchetti.
Registrare dopo la risoluzione di Schedule
In una normale applicazione Laravel,FoundationServiceProvider registra Schedule::class come singleton. La sua creazione chiama resolveConsoleSchedule() del Console Kernel, che applica il fuso orario dell’applicazione e lo store di cache usato dallo scheduler.
Il pacchetto estende questo Schedule condiviso, evitando di creare un proprio new Schedule() e fermarsi lì. Il provider seguente presuppone che Acme\Courier\ corrisponda a src/ tramite il PSR-4 di Composer e che il pacchetto contenga config/courier.php.
callAfterResolving(), se il servizio non è ancora risolto, attende la risoluzione futura; se è già risolto, lo recupera e invoca subito anche la callback. In questo modo la registrazione avviene anche se un altro provider ha usato Schedule prima. Per i dettagli consultate Hook di risoluzione dei servizi nei pacchetti.
runningInConsole() non verifica uno specifico comando Artisan. In questo esempio si esclude l’uso di Schedule tramite HTTP. Inoltre, il provider che registra l’hook non deve essere un provider differito: se boot() non viene eseguito entro il momento necessario, nemmeno l’hook viene registrato.
Registrare un evento ed eseguire un task sono due cose distinte. Caricare questo provider non esegue immediatamente l’heartbeat. La sola registrazione non avvia nemmeno cron o
schedule:work.L’utente attiva esplicitamente il task
Il fileconfig/courier.php del pacchetto imposta lo stato iniziale come disattivato.
schedule.enabled a true. In questo esempio i valori vengono letti al momento della registrazione. Il fuso orario predefinito è UTC; se ne scegliete un altro, tenete conto delle esecuzioni duplicate o mancanti dovute all’ora legale.
Poiché la configurazione viene unita in modo superficiale, anche il registratore specifica il valore predefinito di ogni chiave. Così, anche se una sovrascrittura parziale elimina le altre chiavi dell’array schedule, la registrazione avviene con le impostazioni di base.
Evitare la doppia registrazione nello stesso Schedule
Il seguentesrc/CourierSchedule.php registra un heartbeat minimo che scrive una riga di log. Grazie a WeakMap, questo registratore aggiunge l’evento allo stesso oggetto Schedule una sola volta.
Schedule::call(), exec() e job() aggiungono l’evento a un array. Non sono API che trovano e sostituiscono un evento con lo stesso nome o che eliminano i duplicati.
Il nome dell’evento influisce anche sulla compatibilità dei lock
name() è un alias di description(), ma l’effetto sul nome del lock dipende dal tipo di evento. Di seguito i nomi di mutex predefiniti.
Per i CallbackEvent, assegnate un nome non vuoto prima di
withoutOverlapping() o onOneServer(). Se il nome non è impostato, questi metodi lanciano un’eccezione.
job() di norma usa come nome iniziale il nome della classe del job o simili. Tuttavia, se registrate lo stesso job con argomenti o destinatari diversi, specificate esplicitamente un nome per ciascun destinatario. Cambiare solo gli argomenti non rende automaticamente diverso il nome iniziale.
SyncCatalogJob è un esempio di classe job fornita dal pacchetto. Per l’implementazione dei job consultate Code e job.
Modificando il nome, il comando o l’espressione cron, a seconda del tipo cambia anche l’identificatore del lock. In un deploy in cui convivono processi della vecchia e della nuova versione, la stessa elaborazione potrebbe acquisire lock diversi. Non trattatelo come una semplice modifica del testo visualizzato: gestite il nome del task come una specifica pubblica stabile.
Distinguere onOneServer e withoutOverlapping
onOneServer()sceglie il server incaricato dell’esecuzione per quell’orario. IlCacheSchedulingMutexesaminato aggiunge ore e minuti al nome del mutex dell’evento e lo mantiene con una scadenza di un’ora. È diverso dal lock anti-sovrapposizione che viene rilasciato al termine del task.withoutOverlapping()impedisce la sovrapposizione mentre l’esecuzione precedente è ancora in corso. La scadenza indicata è espressa in minuti e il valore predefinito è 1.440 minuti. Con una scadenza troppo breve, il lock scade prima che l’elaborazione finisca.- Quando
job()accoda un job, il completamento dell’evento pianificato non coincide con il completamento dell’elaborazione del job. Il controllo dei duplicati nei worker va progettato separatamente, ad esempio con i job univoci o il middlewareWithoutOverlappinglato job.
onOneServer() indicate come requisito una cache condivisa tra database, memcached, dynamodb e redis, come specificato dalla documentazione ufficiale. I lock non garantiscono l’esecuzione exactly-once della logica di business: serve anche un’elaborazione che non si rompa se rieseguita.
Risolvere le dipendenze pesanti al momento dell’esecuzione
IlLoggerInterface dell’heartbeat visto sopra viene risolto da CallbackEvent tramite call() del container al momento dell’esecuzione dell’evento. È una configurazione che non scrive log né crea client durante la registrazione dell’hook.
Evitare connessioni esterne e logica di business nel costruttore è importante anche per la Registrazione dei comandi Artisan di un pacchetto e risoluzione delle dipendenze.
Inoltre, poiché
call() e job() sono CallbackEvent, non è possibile usare runInBackground(). Delegate alle code le elaborazioni lunghe oppure, se necessario, scegliete l’esecuzione in background di command().
Non sottrarre le impostazioni globali dell’applicazione
Schedule::useCache() cambia lo store dell’oggetto mutex posseduto da Schedule. Non è un’impostazione limitata agli eventi del pacchetto: influisce anche sugli eventi che condividono lo stesso mutex. Non chiamatelo incondizionatamente nel boot() del pacchetto, ma trattatelo come un’impostazione scelta dall’applicazione che lo usa.
Allo stesso modo, il pacchetto non deve modificare di propria iniziativa Schedule::alwaysOnOneServer(), la sospensione dello scheduler o la politica di esecuzione durante la modalità di manutenzione.
Dopo una modifica della configurazione, creare un nuovo Schedule
Nell’esempio,enabled, l’espressione cron e il fuso orario sono impostazioni lette al momento della registrazione. Cambiare solo i valori di config() per uno Schedule già creato non aggiunge né rimuove eventi e non rilegge la configurazione. Anche il controllo della WeakMap non serve a riconfigurare.
Nei deploy che usano la cache della configurazione, ricostruite la cache e verificate schedule:list in un processo che carica la nuova configurazione. Verificate anche che scheduler a lunga esecuzione o schedule:run che eseguono task sotto il minuto non mantengano il vecchio codice o la vecchia configurazione. Per l’interruzione dei task sotto il minuto durante il deploy consultate Task scheduling.
Testare la registrazione separatamente dall’esecuzione
Quello che segue è un esempio ditests/CourierScheduleTest.php che usa l’autoload Composer del pacchetto e PHPUnit. Il mutex è sostituito da un test double, così da verificare il risultato della registrazione senza cache esterne né cron reale.
Per far passare i test di registrazione, non eseguite tutti i task dell’applicazione con
schedule:run. Separando i test del corpo dei task dai test di integrazione dello scheduler in un ambiente controllato, eviterete gli effetti collaterali di task periodici non correlati.
Pagine correlate
Task scheduling
Frequenza di esecuzione, configurazione di cron, delega alle code e gestione durante i deploy.
Hook di risoluzione dei servizi nei pacchetti
Applicazione a servizi non ancora risolti o già risolti e precauzioni in caso di nuova registrazione.
Fonti primarie consultate
- Documentazione ufficiale di Laravel: Task scheduling
- Documentazione ufficiale di Laravel: sviluppo di pacchetti
- FoundationServiceProvider: registrazione del singleton di Schedule
- Console Kernel: creazione di Schedule e impostazioni predefinite
- ServiceProvider: callAfterResolving()
- Schedule: aggiunta di eventi, creazione differita dei job e condivisione dei mutex
- Event: nome del mutex degli eventi di comando
- CallbackEvent: obbligatorietà del nome e risoluzione delle dipendenze in esecuzione
- CacheEventMutex: lock anti-sovrapposizione e conversione della scadenza
- CacheSchedulingMutex: lock per orario di esecuzione
- Test ufficiali: registrazione degli eventi e fuso orario
- Test ufficiali: creazione differita dal nome della classe del job