Introducción
Los comandos de consola son una herramienta indispensable en el arsenal de cualquier desarrollador Laravel. Nos permiten automatizar tareas recurrentes, procesar datos en segundo plano, y ejecutar operaciones programadas. En este artículo, exploraremos a fondo cómo crear comandos personalizados y cómo utilizarlos con el sistema de Task Scheduling de Laravel para programar su ejecución automática.
Parte 1: Comandos Personalizados en Laravel
Creando tu Primer Comando
Laravel ofrece una forma sencilla de generar nuevos comandos mediante Artisan:
php artisan make:command NombreDelComandoEste comando generará una nueva clase en el directorio app/Console/Commands. Si el directorio no existe, Laravel lo creará automáticamente.
Estructura de un Comando
La estructura básica de un comando incluye:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class EnviarEmails extends Command
{
/**
* El nombre y la firma del comando de consola.
*
* @var string
*/
protected $signature = 'mail:send {usuario}';
/**
* La descripción del comando de consola.
*
* @var string
*/
protected $description = 'Enviar un email de marketing a un usuario';
/**
* Ejecutar el comando de consola.
*/
public function handle()
{
$usuario = $this->argument('usuario');
$this->info("Enviando email a: {$usuario}");
// Lógica para enviar el email
$this->info('Email enviado con éxito!');
}
}Definiendo la Firma del Comando
La propiedad $signature define el nombre del comando y los argumentos que acepta. Esta firma sigue una sintaxis similar a las rutas en Laravel.
Argumentos
Los argumentos se definen entre llaves {}:
<?php
protected $signature = 'mail:send {usuario}';Puedes hacer que los argumentos sean opcionales añadiendo un signo de interrogación ?:
<?php
protected $signature = 'mail:send {usuario?}';También puedes definir valores por defecto:
<?php
protected $signature = 'mail:send {usuario=todos}';Opciones
Las opciones se definen con -- seguido del nombre de la opción:
<?php
protected $signature = 'mail:send {usuario} {--queue}';Para opciones que requieren un valor:
<?php
protected $signature = 'mail:send {usuario} {--queue=}';Con valor por defecto:
<?php
protected $signature = 'mail:send {usuario} {--queue=default}';Atajos para opciones:
<?php
protected $signature = 'mail:send {usuario} {--Q|queue}';Arrays de Entrada
Para argumentos que aceptan múltiples valores:
<?php
protected $signature = 'mail:send {usuarios*}';Para opciones que aceptan múltiples valores:
<?php
protected $signature = 'mail:send {--id=*}';Descripciones de Entradas
Puedes añadir descripciones a los argumentos y opciones:
<?php
protected $signature = 'mail:send
{usuario : El ID del usuario}
{--queue : Si el trabajo debe ser puesto en cola}';El Método Handle
El método handle() es donde reside la lógica principal del comando. Este método se ejecuta cuando se invoca el comando.
<?php
public function handle()
{
// Tu lógica aquí
}Puedes inyectar dependencias en el método handle():
<?php
public function handle(EnviadorEmails $enviador)
{
$enviador->enviar(Usuario::find($this->argument('usuario')));
}Entrada y Salida en Comandos
Obteniendo Entradas
Para obtener argumentos:
<?php
$name = $this->argument('nombre');
$arguments = $this->arguments();Para obtener opciones:
<?php
$name = $this->option('nombre');
$options = $this->options();Solicitando Entradas
El método ask() muestra una pregunta al usuario:
<?php
$name = $this->ask('¿Cuál es tu nombre?');Para contraseñas (entrada oculta):
<?php
$password = $this->secret('¿Cuál es la contraseña?');Para confirmaciones:
<?php
if ($this->confirm('¿Deseas continuar?')) {
// ...
}Para selecciones múltiples:
<?php
$defaultIndex = 1;
$name = $this->choice(
'¿Cuál es tu nombre?',
['Taylor', 'Cursosdesarrolloweb'],
$defaultIndex,
);Generando Salidas
Para mostrar información:
<?php
$this->info('Información mostrada en verde');
$this->error('Error mostrado en rojo');
$this->line('Texto plano sin color');
$this->comment('Comentario mostrado en amarillo');
$this->question('Pregunta mostrada en cian');
$this->warn('Advertencia mostrada en naranja');Para mostrar tablas:
<?php
$this->table(
['Nombre', 'Email'],
User::all(['nombre', 'email'])->toArray()
);Para barras de progreso:
<?php
$users = $this->withProgressBar(User::all(), fn (User $user) => $this->runTask($user));Comandos en Cierre (Closure Commands)
Los comandos basados en cierres son una alternativa a definir comandos como clases:
<?php
// En routes/console.php
Artisan::command('mail:send {usuario}', function (string $user) {
$this->info("Enviando email a: {$user}!");
});Puedes añadir una descripción usando el método purpose():
<?php
Artisan::command('mail:send {usuario}', function (string $user) {
// ...
})->purpose('Enviar un email de marketing a un usuario');Registrando Comandos
Laravel registra automáticamente todos los comandos en el directorio app/Console/Commands. Si tienes comandos en otras ubicaciones, puedes registrarlos en bootstrap/app.php:
<?php
->withCommands([
__DIR__.'/../app/Domain/Orders/Commands',
])También puedes registrar comandos específicos:
<?php
use App\Domain\Orders\Commands\SendEmails;
->withCommands([
SendEmails::class,
])Comandos Aislables
A veces, necesitas asegurarte de que solo una instancia de un comando se ejecute a la vez. Para lograr esto, puedes implementar la interfaz Illuminate\Contracts\Console\Isolatable:
<?php
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Isolatable;
class SendEmails extends Command implements Isolatable
{
// ...
}Para ejecutar el comando aislado:
php artisan mail:send 1 --isolatedParte 2: Task Scheduling en Laravel
Configuración Básica
El programador de tareas de Laravel te permite definir tu programación de comandos directamente en el código de tu aplicación. Esto elimina la necesidad de crear entradas cron manualmente.
Las tareas programadas se definen generalmente en el archivo routes/console.php:
<?php
use Illuminate\Support\Facades\Schedule;
Schedule::command('emails:send')->daily();Definiendo Horarios
Laravel ofrece una amplia variedad de métodos para definir la frecuencia de ejecución de tus tareas:
Frecuencias Comunes
<?php
// Diariamente a medianoche
Schedule::command('backup:clean')->daily();
// Diariamente a una hora específica (13:00)
Schedule::command('backup:clean')->dailyAt('13:00');
// Diariamente dos veces al día
Schedule::command('backup:clean')->twiceDaily(1, 13);
// Cada semana
Schedule::command('backup:clean')->weekly();
// Cada mes
Schedule::command('backup:clean')->monthly();
// Cada minuto
Schedule::command('backup:clean')->everyMinute();
// Cada cinco minutos
Schedule::command('backup:clean')->everyFiveMinutes();
// Cada hora
Schedule::command('backup:clean')->hourly();Expresiones Cron Personalizadas
Para frecuencias más específicas:
<?php
Schedule::command('backup:clean')->cron('* * * * *');Tipos de Tareas Programables
Comandos Artisan
<?php
Schedule::command('emails:send Cursosdesarrolloweb --force')->daily();
// Con clase
use App\Console\Commands\SendEmailsCommand;
Schedule::command(SendEmailsCommand::class, ['Cursosdesarrolloweb', '--force'])->daily();Trabajos en Cola
<?php
use App\Jobs\Heartbeat;
Schedule::job(new Heartbeat)->everyFiveMinutes();
// Con cola y conexión específicas
Schedule::job(new Heartbeat, 'heartbeats', 'sqs')->everyFiveMinutes();Comandos del Sistema
<?php
Schedule::exec('node /home/forge/script.js')->daily();Cierres (Closure)
<?php
Schedule::call(function () {
DB::table('recent_users')->delete();
})->daily();Restricciones Adicionales
Restricciones de Días
<?php
// Solo días laborables
Schedule::command('emails:send')->weekdays();
// Solo fines de semana
Schedule::command('emails:send')->weekends();
// Días específicos
Schedule::command('emails:send')->mondays();
Schedule::command('emails:send')->tuesdays();
// ...y así sucesivamente
// Múltiples días
Schedule::command('emails:send')->days([Schedule::MONDAY, Schedule::WEDNESDAY]);Restricciones de Horario
<?php
// Entre horas específicas
Schedule::command('emails:send')
->hourly()
->between('8:00', '17:00');
// Excepto entre horas específicas
Schedule::command('emails:send')
->hourly()
->unlessBetween('23:00', '4:00');Restricciones Condicionales
<?php
Schedule::command('emails:send')
->daily()
->when(function () {
return true; // Tu condición aquí
});
// Skip es lo opuesto a when
Schedule::command('emails:send')
->daily()
->skip(function () {
return true; // Tu condición aquí
});Restricciones de Entorno
<?php
Schedule::command('emails:send')
->daily()
->environments(['staging', 'production']);Evitando Superposiciones de Tareas
Para evitar que una tarea se ejecute si la instancia anterior aún está en ejecución:
<?php
Schedule::command('emails:send')->withoutOverlapping();
// Con tiempo de expiración personalizado (en minutos)
Schedule::command('emails:send')->withoutOverlapping(10);Ejecutando Tareas en un Solo Servidor
Para entornos con múltiples servidores, puedes asegurarte de que una tarea programada se ejecute solo en un servidor:
<?php
Schedule::command('report:generate')
->fridays()
->at('17:00')
->onOneServer();
// Con caché personalizada
Schedule::command('recipes:sync')
->everyThirtyMinutes()
->onOneServer()
->useCache('database');Tareas en Segundo Plano
Para ejecutar tareas en segundo plano:
<?php
Schedule::command('analytics:report')
->daily()
->runInBackground();Grupos de Tareas Programadas
Para aplicar la misma configuración a múltiples tareas:
<?php
Schedule::daily()
->onOneServer()
->timezone('Europe/Madrid')
->group(function () {
Schedule::command('emails:send --force');
Schedule::command('emails:prune');
});Salida de Tareas
Para guardar la salida de una tarea:
<?php
Schedule::command('emails:send')
->daily()
->sendOutputTo($pathFile);
// Añadir al archivo existente
Schedule::command('emails:send')
->daily()
->appendOutputTo($pathFile);Para enviar la salida por email:
<?php
Schedule::command('report:generate')
->daily()
->sendOutputTo($rutaArchivo)
->emailOutputTo('[email protected]');
// Solo en caso de fallo
Schedule::command('report:generate')
->daily()
->emailOutputOnFailure('[email protected]');Hooks de Tareas
Para ejecutar código antes o después de una tarea:
<?php
Schedule::command('emails:send')
->daily()
->before(function () {
// Antes de ejecutar la tarea...
})
->after(function () {
// Después de ejecutar la tarea...
});
// En caso de éxito o fallo
Schedule::command('emails:send')
->daily()
->onSuccess(function () {
// La tarea tuvo éxito...
})
->onFailure(function () {
// La tarea falló...
});Notificaciones via URL
Para notificar a un servicio externo:
<?php
Schedule::command('emails:send')
->daily()
->pingBefore($url) // Antes de ejecutar
->thenPing($url); // Después de ejecutar
// Solo en caso de éxito o fallo
Schedule::command('emails:send')
->daily()
->pingOnSuccess($successUrl)
->pingOnFailure($failureUrl);Ejecutando el Scheduler
Para que el programador de tareas funcione, debes configurar un solo trabajo cron en tu servidor que ejecute el comando schedule:run cada minuto:
* * * * * cd /ruta-a-tu-proyecto && php artisan schedule:run >> /dev/null 2>&1Tareas Sub-Minuto
Laravel también permite programar tareas que se ejecuten en intervalos inferiores a un minuto:
<?php
Schedule::call(function () {
// Tu tarea aquí
})->everySecond();
// Cada 5 segundos
Schedule::call(function () {
// Tu tarea aquí
})->everyFiveSeconds();
// Cada 10 segundos
Schedule::call(function () {
// Tu tarea aquí
})->everyTenSeconds();Para tareas sub-minuto, es recomendable utilizar trabajos en cola o comandos en segundo plano:
<?php
use App\Jobs\DeleteRecentUsers;
Schedule::job(new DeleteRecentUsers)->everyTenSeconds();
Schedule::command('recent-users:delete')->everyTenSeconds()->runInBackground();Ejecutando el Scheduler Localmente
Durante el desarrollo, puedes usar el comando schedule:work:
php artisan schedule:workEste comando ejecutará el programador en primer plano y lo invocará cada minuto hasta que termines el comando.
Conclusión
Los comandos personalizados y el Task Scheduling en Laravel son herramientas fundamentales para la automatización de tareas y procesos. Dominando estos conceptos, podrás crear aplicaciones más eficientes, automatizar tareas repetitivas y programar procesos en segundo plano de manera efectiva.
La combinación de comandos bien diseñados con el poderoso sistema de programación de tareas de Laravel proporciona una solución robusta para cualquier necesidad de automatización en tus aplicaciones.
Curso Laravel 12
Completo 2026
El único curso 100% actualizado que incluye Laravel 12, Livewire 3, Vue 3, React 19 e Inertia 2. Aprende con proyectos reales y las últimas funcionalidades.
star Incluido en cualquier suscripción