Task scheduling is a fundamental feature of modern web applications that provides numerous benefits for automation, maintenance, and system efficiency. Let’s explore the key reasons why you should use task scheduling in Laravel applications.
Automation
- Runs repetitive tasks (emails, reports, cleanups) automatically without manual intervention.
Performance Optimization
- Executes heavy tasks (like backups) during off-peak hours to avoid slowing down users.
Reliability
- Ensures critical tasks (e.g., daily DB backups) run on time, every time, eliminating human error.
Maintenance
- Automates system health tasks (cache clearing, log rotation) to keep apps running smoothly.
Queue Management
- Controls when background jobs (e.g., order processing) run for better resource usage.
Timezone Handling
- Schedules tasks based on business hours or user locations (e.g., “Send at 9 AM local time”).
Error Handling
- Auto-retries failed tasks and notifies developers via logs/emails.
Simplicity
- Replaces complex cron syntax with readable Laravel methods like
->daily()or->everyFiveMinutes().
Step-by-Step Implementation
Step 1: Set Up the Cron Entry on Your Server
First, you need to add a cron entry that runs the Laravel schedule. On your server, run:
crontab -e
Add this line (replace
/path-to-your-projectwith your actual project path):
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
What This Does
1. * * * * *
- Runs the command every minute (cron syntax for “always”).
- You can use Cron Guru, a tool that simplifies the creation and understanding of cron expressions used for scheduling tasks in Unix-like systems.
2. cd /path-to-your-project
- Navigates to your Laravel root directory (where
artisanlives). - Replace with your actual path (e.g.,
/var/www/myapp).
3. php artisan schedule:run
- Laravel’s scheduler — checks
routes/console.phpand runs any due tasks.
4. >> /dev/null 2>&1
- Silences output (no spam in server logs).
>> /dev/nullhides normal output.2>&1redirects errors to the same void.
Step 2: Define Your Scheduled Tasks
All scheduled tasks are defined in the routes/console.php file. Here’s a complete example with different types of scheduled tasks:
<?php
use App\Jobs\SendDailyReports;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schedule;
// Example 1: Run a command daily at midnight
Schedule::command('inspire')->daily();
// Example 2: Run a custom command every hour
Schedule::command('orders:process')->hourly();
// Example 3: Run a closure every minute
Schedule::call(function () {
Log::info('This task runs every minute');
})->everyMinute();
// Example 4: Run a job on weekdays at 8:00 AM
Schedule::job(new SendDailyReports)->weekdays()->at('08:00');
// Example 5: Run a command with specific timezone
Schedule::command('notifications:send')
->timezone('America/New_York')
->dailyAt('13:00');
// Example 6: Run task between specific hours
Schedule::command('backup:run')
->everyThirtyMinutes()
->between('8:00', '17:00');
// Example 7: Run task only when environment is production
Schedule::command('queue:work --stop-when-empty')
->everyFiveMinutes()
->environments(['production']);
// Example 8: The exec method may be used to issue a command to the operating system:
Schedule::exec('node /home/forge/script.js')->daily();
You can find all available schedule frequency options in the Laravel Scheduling Documentation
Step 3: Create a Custom Command
If you want to schedule a custom command, first create it:
php artisan make:command ProcessOrders --command=orders:process
Then define the command logic in
app/Console/Commands/ProcessOrders.php:
<?php
namespace App\Console\Commands;
use App\Models\Order;
use Exception;
use Illuminate\Console\Command;
class ProcessOrders extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'orders:process';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Process pending orders';
/**
* Execute the console command.
*/
public function handle(): void
{
try {
$this->info("Process started.");
$orders = Order::where('status', 'pending')->get();
foreach ($orders as $order) {
// Process each order
$order->update(['status' => 'processed']);
$this->info("Processed order #{$order->id}.");
}
$this->info('All pending orders processed successfully.');
$this->info('Process ended.');
} catch (Exception $exception) {
$this->error($exception->getMessage());
}
}
}
Define your command in routes/console.phpfile.
// Option 1: Using Command Signature (String)
Schedule::command('orders:process')->daily();
// Option 2: Using Command Class
Schedule::command(ProcessOrders::class)->daily();
Step 4: Test Your Scheduled Tasks
Before relying on the cron, test your tasks:
1. Test individual commands:
php artisan orders:process
2. Test the scheduler (runs all due tasks):
php artisan schedule:run
3. For debugging, add output:
$schedule->command('orders:process')
->hourly()
->sendOutputTo(storage_path('logs/orders.log'));
Advanced Scheduling Options
Task Hooks
You can add code to run before and after a task:
$schedule->command('orders:process')
->daily()
->before(function () {
Log::info('About to process orders');
})
->after(function () {
Log::info('Finished processing orders');
});
Prevent Task Overlaps
Prevent a task from running if the previous instance is still running:
$schedule->command('emails:send')
->everyMinute()
->withoutOverlapping();
Run Tasks on One Server
If your app runs on multiple servers, ensure a task runs on only one server:
$schedule->command('report:generate')
->daily()
->onOneServer();
Monitoring Scheduled Tasks
View scheduled tasks:
php artisan schedule:list
Log all scheduler activity:
public function handle(): void
{
try {
Log::info('Process started.');
$orders = Order::where('status', 'pending')->get();
foreach ($orders as $order) {
// Process each order
$order->update(['status' => 'processed']);
Log::info("Processed order #{$order->id}.");
}
Log::info('All pending orders processed successfully.');
Log::info('Process ended.');
} catch (Exception $exception) {
Log::error($exception->getMessage());
}
}
Best Practices
- Keep task durations short: Long-running tasks should be queued.
- Use meaningful task names: Makes logging and debugging easier.
- Handle failures gracefully: Use try-catch blocks in your commands.
- Monitor task execution: Set up alerts for failed tasks.
- Document your tasks: Add comments explaining what each scheduled task does.
If you found this helpful, feel free to share or drop a comment. Happy coding with Laravel! 🧱✨
Free resources for this topic
Code snippets and fixes for this topic
Get one practical tip every week
New tutorials, fixes and free cheat sheets from DEV Talk, straight to your inbox. No spam, unsubscribe in one click.
Free download: Laravel interview questions (PDF)
Have a question about this post?
Ask the community: other developers and the author can answer.
Get notified about new articles
One click, no email needed. Turn it off anytime with the bell at the top.
Get new articles on your iPhone
Add DEV Talk to your Home Screen, open it, then tap the bell.
Enjoying the content?
If this article helped you, you can support the author with a coffee. It keeps new posts coming.
Comments 0
No comments yet
Be the first to share your thoughts.