Saltar al contenido

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 NombreDelComando

Este 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 --isolated

Parte 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>&1

Tareas 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:work

Este 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.

school Curso completo

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.

access_time 8 horas de contenido
layers 4 tecnologías en 1
update 100% actualizado
code Proyectos prácticos
Ver Curso Laravel 12 arrow_forward

star Incluido en cualquier suscripción

Rutas de aprendizaje