• Introducción
  • Definición de programaciones
    • Programación de comandos Artisan
    • Programación de trabajos en cola
    • Programación de comandos Shell
    • Opciones de frecuencia de programación
    • Zonas horarias
    • Prevención de solapamientos de tareas
    • .

    • Ejecución de tareas en un servidor
    • Tareas en segundo plano
    • Modo de mantenimiento
  • Ejecución del programador
    • Ejecución local del programador
  • Salida de tareas
  • Ganchos de tareas

Introducción

En el pasado, es posible que haya escrito una entrada de configuración de cron para cada tarea que necesitaba programar en su servidor. Sin embargo, esto puede convertirse rápidamente en un dolor porque su programación de tareas ya no está en el control de origen y debe SSH en su servidor para ver sus entradas cron existentes o añadir entradas adicionales.

El planificador de comandos de Laravel ofrece un nuevo enfoque para la gestión de las tareas programadas en su servidor. El programador le permite definir de forma fluida y expresiva su programación de comandos dentro de su propia aplicación Laravel. Cuando se utiliza el planificador, sólo se necesita una única entrada cron en su servidor. Su programación de tareas se define en el método app/Console/Kernel.php del archivo schedule. Para ayudarle a empezar, un ejemplo simple se define dentro del método.

Definiendo Horarios

Usted puede definir todas sus tareas programadas en el método schedule de la clase App\Console\Kernel de su aplicación. Para empezar, veamos un ejemplo. En este ejemplo, programaremos un cierre para que sea llamado cada día a medianoche. Dentro del cierre ejecutaremos una consulta a la base de datos para limpiar una tabla:

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

Además de programar usando cierres, también puedes programar objetos invocables. Los objetos invocables son simples clases de PHP que contienen un método __invoke:

$schedule->call(new DeleteRecentUsers)->daily();

Si desea ver una visión general de sus tareas programadas y la próxima vez que están programadas para ejecutarse, puede utilizar el comando schedule:list Artisan:

php artisan schedule:list

Programación de comandos Artisan

Además de programar cierres, también puede programar comandos Artisan y comandos del sistema. Por ejemplo, puede utilizar el método command para programar un comando de Artisan utilizando el nombre o la clase del comando.

Cuando se programan comandos de Artisan utilizando el nombre de la clase del comando, puede pasar una matriz de argumentos de línea de comandos adicionales que deben proporcionarse al comando cuando se invoca:

use App\Console\Commands\SendEmailsCommand;$schedule->command('emails:send Taylor --force')->daily();$schedule->command(SendEmailsCommand::class, )->daily();

Programación de trabajos en cola

El método job puede utilizarse para programar un trabajo en cola. Este método proporciona una manera conveniente de programar trabajos en cola sin utilizar el método call para definir los cierres para poner en cola el trabajo:

use App\Jobs\Heartbeat;$schedule->job(new Heartbeat)->everyFiveMinutes();

Se puede proporcionar un segundo y tercer argumento opcional al método job que especifica el nombre de la cola y la conexión de la cola que se debe utilizar para poner en cola el trabajo:

use App\Jobs\Heartbeat;// Dispatch the job to the "heartbeats" queue on the "sqs" connection...$schedule->job(new Heartbeat, 'heartbeats', 'sqs')->everyFiveMinutes();

Programación de comandos Shell

El método exec puede utilizarse para emitir un comando al sistema operativo:

$schedule->exec('node /home/forge/script.js')->daily();

Opciones de frecuencia de programación

Ya hemos visto algunos ejemplos de cómo se puede configurar una tarea para que se ejecute a intervalos específicos. Sin embargo, hay muchas más frecuencias de programación de tareas que puede asignar a una tarea:

Ejecutar la tarea en un horario cron personalizado

Ejecutar la tarea cada diez minutos

Ejecutar la tarea cada quince minutos

Ejecutar la tarea todos los días a medianoche

Ejecutar la tarea todos los días a las 13:00

Ejecutar la tarea cada semana el lunes a las 8:00

Ejecutar la tarea el primer día de cada mes a las 00:00

Ejecutar la tarea el último día del mes a las 15:00

Ejecutar la tarea el primer día de cada año a las 00:00

Método Descripción
->cron('* * * * *');
->everyMinute(); Ejecutar la tarea cada minuto
->everyTwoMinutes(); Ejecutar la tarea cada dos minutos
->everyThreeMinutes(); Ejecutar la tarea cada tres minutos
->everyFourMinutes(); Ejecutar la tarea cada cuatro minutos
->everyFiveMinutes(); Ejecutar la tarea cada cinco minutos
->everyTenMinutes();
->everyFifteenMinutes();
->everyThirtyMinutes(); Ejecutar la tarea cada treinta minutos
->hourly(); Ejecutar la tarea cada hora
->hourlyAt(17); Ejecutar la tarea cada hora a las 17 horas
->everyTwoHours(); Ejecutar la tarea cada dos horas
->everyThreeHours(); Ejecutar la tarea cada tres horas
->everyFourHours(); Ejecutar la tarea cada cuatro horas
->everySixHours(); Ejecutar la tarea cada seis horas
->daily();
->dailyAt('13:00');
->twiceDaily(1, 13); Ejecutar la tarea todos los días a la 1:00 & 13:00
->weekly(); Ejecutar la tarea todos los domingos a las 00:00
->weeklyOn(1, '8:00');
->monthly();
->monthlyOn(4, '15:00'); Ejecutar la tarea cada mes el día 4 a las 15:00
->twiceMonthly(1, 16, '13:00'); Ejecutar la tarea mensualmente los días 1 y 16 a las 13:00
->lastDayOfMonth('15:00');
->quarterly(); Ejecutar la tarea el primer día de cada trimestre a las 00:00
->yearly();
->yearlyOn(6, 1, '17:00'); Ejecutar la tarea cada año el 1 de junio a las 17:00
->timezone('America/New_York'); Establezca la zona horaria para la tarea

Estos métodos pueden combinarse con restricciones adicionales para crear programaciones aún más precisas que sólo se ejecuten en determinados días de la semana. Por ejemplo, puede programar un comando para que se ejecute semanalmente el lunes:

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

A continuación se incluye una lista de restricciones de programación adicionales:

Limitar la tarea a los días de la semana

Método Descripción
->weekdays();
->weekends(); Limitar la tarea a los fines de semana
->sundays(); Limitar la tarea a los domingos
->mondays(); Limitar la tarea al lunes
->tuesdays(); Limitar la tarea al martes
->wednesdays(); Limitar la tarea al miércoles
->thursdays(); Limitar la tarea al jueves
->fridays(); Limitar la tarea al viernes
->saturdays(); Limitar la tarea al sábado
->days(array|mixed); Limitar la tarea a días específicos
->between($startTime, $endTime); Limitar la tarea para que se ejecute entre las horas de inicio y fin
->unlessBetween($startTime, $endTime); Limitar la tarea para que no se ejecute entre las horas de inicio y final
->when(Closure); Limitar la tarea basándose en una prueba de verdad
->environments($env); Limitar la tarea a determinados entornos

Limitaciones de días

El método days puede utilizarse para limitar la ejecución de una tarea a días específicos de la semana. Por ejemplo, puede programar un comando para que se ejecute cada hora los domingos y los miércoles:

$schedule->command('emails:send') ->hourly() ->days();

Alternativamente, puede utilizar las constantes disponibles en la clase Illuminate\Console\Scheduling\Schedule al definir los días en los que una tarea debe ejecutarse:

use Illuminate\Console\Scheduling\Schedule;$schedule->command('emails:send') ->hourly() ->days();

Restricciones de Hora

El método between puede utilizarse para limitar la ejecución de una tarea basada en la hora del día:

$schedule->command('emails:send') ->hourly() ->between('7:00', '22:00');

De forma similar, el método unlessBetween puede utilizarse para excluir la ejecución de una tarea durante un periodo de tiempo:

$schedule->command('emails:send') ->hourly() ->unlessBetween('23:00', '4:00');

Constricciones de prueba de verdad

El método when puede utilizarse para limitar la ejecución de una tarea basándose en el resultado de una prueba de verdad dada. En otras palabras, si el cierre dado devuelve true, la tarea se ejecutará siempre y cuando no haya otras condiciones de restricción que impidan la ejecución de la tarea:

$schedule->command('emails:send')->daily()->when(function () { return true;});

El método skip puede verse como el inverso de when. Si el método skip devuelve true, la tarea programada no se ejecutará:

$schedule->command('emails:send')->daily()->skip(function () { return true;});

Cuando se utilizan métodos when encadenados, la orden programada sólo se ejecutará si todas las condiciones when devuelven true.

Restricciones de entorno

El método environments puede utilizarse para ejecutar tareas sólo en los entornos dados (como se define por la variable de entorno APP_ENV):

$schedule->command('emails:send') ->daily() ->environments();

Zonas horarias

Usando el método timezone, puede especificar que la hora de una tarea programada debe ser interpretada dentro de una zona horaria determinada:

$schedule->command('report:generate') ->timezone('America/New_York') ->at('2:00')

Si está asignando repetidamente la misma zona horaria a todas sus tareas programadas, es posible que desee definir un método scheduleTimezone en su clase App\Console\Kernel. Este método debe devolver la zona horaria por defecto que se debe asignar a todas las tareas programadas:

/** * Get the timezone that should be used by default for scheduled events. * * @return \DateTimeZone|string|null */protected function scheduleTimezone(){ return 'America/Chicago';}

{nota} Recuerde que algunas zonas horarias utilizan el horario de verano. Cuando se produce el cambio de horario de verano, la tarea programada puede ejecutarse dos veces o incluso no ejecutarse. Por esta razón, recomendamos evitar la programación de zonas horarias cuando sea posible.

Prevención de solapamientos de tareas

Por defecto, las tareas programadas se ejecutarán incluso si la instancia anterior de la tarea sigue en marcha. Para evitarlo, puede utilizar el método withoutOverlapping:

$schedule->command('emails:send')->withoutOverlapping();

En este ejemplo, el comando emails:send Artisan se ejecutará cada minuto si no está ya en marcha. El método withoutOverlapping es especialmente útil si tiene tareas que varían drásticamente en su tiempo de ejecución, lo que le impide predecir exactamente cuánto tiempo tomará una tarea determinada.

Si es necesario, puede especificar cuántos minutos deben pasar antes de que expire el bloqueo «sin superposición». Por defecto, el bloqueo expirará después de 24 horas:

$schedule->command('emails:send')->withoutOverlapping(10);

Ejecución de tareas en un servidor

{nota} Para utilizar esta función, su aplicación debe utilizar el controlador de caché database, memcached, dynamodb o redis como controlador de caché predeterminado de su aplicación. Además, todos los servidores deben comunicarse con el mismo servidor de caché central.

Si el programador de su aplicación se ejecuta en varios servidores, puede limitar un trabajo programado para que sólo se ejecute en un único servidor. Por ejemplo, suponga que tiene una tarea programada que genera un nuevo informe cada viernes por la noche. Si el programador de tareas se ejecuta en tres servidores de trabajadores, la tarea programada se ejecutará en los tres servidores y generará el informe tres veces. Para indicar que la tarea debe ejecutarse sólo en un servidor, utilice el método onOneServer al definir la tarea programada. El primer servidor que obtenga la tarea asegurará un bloqueo atómico en el trabajo para evitar que otros servidores ejecuten la misma tarea al mismo tiempo:

$schedule->command('report:generate') ->fridays() ->at('17:00') ->onOneServer();

Tareas de fondo

Por defecto, varias tareas programadas al mismo tiempo se ejecutarán secuencialmente según el orden en que se definan en su método schedule. Si tiene tareas de larga duración, esto puede hacer que las tareas posteriores se inicien mucho más tarde de lo previsto. Si desea ejecutar tareas en segundo plano para que todas se ejecuten simultáneamente, puede utilizar el método runInBackground:

$schedule->command('analytics:report') ->daily() ->runInBackground();

{nota} El método runInBackground sólo puede utilizarse cuando se programan tareas a través de los métodos command y exec.

Modo de mantenimiento

Las tareas programadas de su aplicación no se ejecutarán cuando la aplicación esté en modo de mantenimiento, ya que no queremos que sus tareas interfieran con cualquier mantenimiento inacabado que pueda estar realizando en su servidor. Sin embargo, si desea forzar la ejecución de una tarea incluso en modo de mantenimiento, puede llamar al método evenInMaintenanceMode al definir la tarea:

$schedule->command('emails:send')->evenInMaintenanceMode();

Ejecución del programador

Ahora que hemos aprendido a definir las tareas programadas, vamos a discutir cómo ejecutarlas realmente en nuestro servidor. El comando schedule:run Artisan evaluará todas tus tareas programadas y determinará si necesitan ejecutarse basándose en la hora actual del servidor.

Así que, al usar el programador de Laravel, sólo necesitamos añadir una única entrada de configuración cron a nuestro servidor que ejecute el comando schedule:run cada minuto. Si no sabes cómo añadir entradas cron a tu servidor, considera usar un servicio como Laravel Forge que puede gestionar las entradas cron por ti:

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

Ejecutando el planificador localmente

Típicamente, no añadirías una entrada cron del planificador a tu máquina de desarrollo local. En su lugar, puede utilizar el comando schedule:work Artisan. Este comando se ejecutará en primer plano e invocará el planificador cada minuto hasta que usted termine el comando:

php artisan schedule:work

Salida de la tarea

El planificador de Laravel proporciona varios métodos convenientes para trabajar con la salida generada por las tareas programadas. En primer lugar, utilizando el método sendOutputTo, puede enviar la salida a un archivo para su posterior inspección:

$schedule->command('emails:send') ->daily() ->sendOutputTo($filePath);

Si desea añadir la salida a un archivo determinado, puede utilizar el método appendOutputTo:

$schedule->command('emails:send') ->daily() ->appendOutputTo($filePath);

Usando el método emailOutputTo, puede enviar la salida a una dirección de correo electrónico de su elección. Antes de enviar por correo electrónico la salida de una tarea, debe configurar los servicios de correo electrónico de Laravel:

$schedule->command('report:generate') ->daily() ->sendOutputTo($filePath) ->emailOutputTo('');

Si sólo desea enviar por correo electrónico la salida si el Artisan programado o el comando del sistema termina con un código de salida distinto de cero, utilice el método emailOutputOnFailure:

$schedule->command('report:generate') ->daily() ->emailOutputOnFailure('');

{nota} Los métodos emailOutputTo, emailOutputOnFailure, sendOutputTo y appendOutputTo son exclusivos de los métodos command y exec.

Hooks de tareas

Usando los métodos before y after, puede especificar el código que se ejecutará antes y después de que se ejecute la tarea programada:

$schedule->command('emails:send') ->daily() ->before(function () { // The task is about to execute... }) ->after(function () { // The task has executed... });

Los métodos onSuccess y onFailure permiten especificar el código que se ejecutará si la tarea programada tiene éxito o falla. Un fallo indica que el comando programado de Artisan o del sistema terminó con un código de salida distinto de cero:

$schedule->command('emails:send') ->daily() ->onSuccess(function () { // The task succeeded... }) ->onFailure(function () { // The task failed... });

Si la salida está disponible desde su comando, puede acceder a ella en sus ganchos after, onSuccess o onFailure indicando una instancia Illuminate\Support\Stringable como el argumento $output de la definición de cierre de su gancho:

use Illuminate\Support\Stringable;$schedule->command('emails:send') ->daily() ->onSuccess(function (Stringable $output) { // The task succeeded... }) ->onFailure(function (Stringable $output) { // The task failed... });

Ping URLs

Usando los métodos pingBefore y thenPing, el programador puede hacer ping automáticamente a una URL dada antes o después de que se ejecute una tarea. Este método es útil para notificar a un servicio externo, como Envoyer, que su tarea programada está comenzando o ha terminado de ejecutarse:

$schedule->command('emails:send') ->daily() ->pingBefore($url) ->thenPing($url);

Los métodos pingBeforeIf y thenPingIf pueden utilizarse para hacer ping a una URL dada sólo si una condición dada es true:

$schedule->command('emails:send') ->daily() ->pingBeforeIf($condition, $url) ->thenPingIf($condition, $url);

Los métodos pingOnSuccess y pingOnFailure pueden utilizarse para hacer ping a una URL dada sólo si la tarea tiene éxito o falla. Un fallo indica que el comando programado de Artisan o del sistema terminó con un código de salida distinto de cero:

$schedule->command('emails:send') ->daily() ->pingOnSuccess($successUrl) ->pingOnFailure($failureUrl);

Todos los métodos de ping requieren la biblioteca Guzzle HTTP. Guzzle se instala normalmente en todos los nuevos proyectos de Laravel por defecto, pero, puede instalar manualmente Guzzle en su proyecto utilizando el gestor de paquetes Composer si se ha eliminado accidentalmente:

composer require guzzlehttp/guzzle