Trigger Laravel scheduled tasks when users visit your application - Perfect for hosting platforms without cron job support (or that make you pay for extra agents etc. to enable it)
A Laravel package that executes Artisan commands when users visit your application, based on configurable time intervals. Perfect for Digital Ocean App Platform, Heroku, and other hosting providers that don't initially support traditional cron jobs (without adding extra worker, etc.).
Developed by Edwin Klesman of EEKAY ONLINE
- β Automatic backups triggered by user activity
- β Cache warming when site gets traffic
- β Data cleanup jobs on regular intervals
- β Report generation without cron access
- β Any scheduled task on platforms without cron
- π User-driven scheduling - Tasks run when users visit your site
- β±οΈ Configurable intervals - Set minutes or hours between executions
- π Lock mechanism - Prevents duplicate executions
- π Environment aware - Automatically disabled in local/development
- βοΈ Easy configuration - Simple config file and environment variables
- π Health monitoring - Built-in command to check task status
- π Notifications - Log, Slack, or email support
- π« Smart skipping - Ignores API routes, assets, and AJAX requests
- πͺ Laravel 10+ - Built for modern Laravel applications
- PHP >= 8.2
- Laravel >= 10.0
- Cache driver (file, redis, or database)
Install the package via Composer:
composer require eekay/laravel-usage-triggerphp artisan vendor:publish --provider="Eekay\LaravelUsageTrigger\ScheduledTriggerServiceProvider" --tag="config"This will create config/scheduled-trigger.php.
Add these to your .env file:
# Enable/disable usage trigger (default: false)
SCHEDULED_TRIGGER_ENABLED=true
# Tasks will be configured in config/scheduled-trigger.phpOpen config/scheduled-trigger.php:
return [
// Enable/disable the trigger globally
'enabled' => env('SCHEDULED_TRIGGER_ENABLED', false),
// Skip trigger on these routes
'skip_routes' => ['api/*', 'ping', 'admin/*'],
// Skip trigger on AJAX requests
'skip_ajax' => true,
// Define your scheduled tasks
'tasks' => [
'backup' => [
'enabled' => true,
'command' => 'backup:run',
'interval_minutes' => 1440, // 24 hours
'lock_duration_seconds' => 300,
'async' => true,
'retries' => 3,
'per_day_limit' => 3,
],
'cache-warm' => [
'enabled' => true,
'command' => 'cache:warm',
'interval_minutes' => 60,
'parameters' => ['--force'],
],
],
];| Option | Type | Required | Default | Description |
|---|---|---|---|---|
enabled |
bool | Yes | - | Enable/disable this specific task |
command |
string | Yes | - | Artisan command to execute |
interval_minutes |
int | Yes | - | Minutes between executions |
lock_duration_seconds |
int | No | 300 | Lock timeout in seconds |
async |
bool | No | false | Run asynchronously via queue |
retries |
int | No | 0 | Max retry attempts on failure |
per_day_limit |
int | No | null | Max executions per day |
parameters |
array | No | [] | Command parameters |
Register the middleware in app/Http/Kernel.php:
protected $middlewareGroups = [
'web' => [
// ... other middleware
\Eekay\LaravelUsageTrigger\Middleware\ScheduledTriggerMiddleware::class,
],
];This package is perfect for triggering backups on hosting platforms without cron support:
// config/scheduled-trigger.php
'tasks' => [
'backup' => [
'enabled' => true,
'command' => 'backup:run',
'interval_minutes' => 1440, // Run every 24 hours
'async' => true,
'per_day_limit' => 1, // Only once per day
],
],When a user visits your site, the middleware checks:
- β Is backup enabled?
- β Has it been 24 hours since last backup?
- β Not exceeded daily limit?
- β No backup already running?
If all conditions are met β Backup starts automatically!
php artisan scheduled-trigger:statusOutput:
+----------+--------+-------------------------------------+---------------------+
| Task | Status | Last Run | Next Run (approx) |
+----------+--------+-------------------------------------+---------------------+
| backup | Active | 2025-10-30 10:00:00 | 2025-10-31 10:00:00 |
| cleanup | Active | Never | Next user visit |
+----------+--------+-------------------------------------+---------------------+
php artisan scheduled-trigger:listphp artisan scheduled-trigger:clearUseful for testing or resetting task timers.
Configure notifications in config/scheduled-trigger.php:
'notifications' => [
'enabled' => true,
'channels' => ['log', 'slack'], // or 'mail'
'notify_on' => [
'success' => true,
'failure' => true,
'retry' => false,
],
'slack' => [
'webhook_url' => env('SLACK_WEBHOOK_URL'),
'channel' => '#backups',
],
'mail' => [
'to' => 'admin@example.com',
'from' => env('MAIL_FROM_ADDRESS'),
],
],Local/Development:
- Package is automatically disabled
- Set
SCHEDULED_TRIGGER_ENABLED=trueto test locally
Production:
- Enabled by default when
SCHEDULED_TRIGGER_ENABLEDis not set - Use environment variable to explicitly control
Prevent tasks from running too frequently:
'backup' => [
'enabled' => true,
'command' => 'backup:run',
'interval_minutes' => 60,
'per_day_limit' => 3, // Max 3 times per day
],Automatically retry failed tasks:
'backup' => [
'enabled' => true,
'command' => 'backup:run',
'retries' => 3, // Try up to 3 times on failure
],Use queue for non-blocking execution:
'backup' => [
'enabled' => true,
'command' => 'backup:run',
'async' => true, // Run in background queue
],Pass arguments to your commands:
'cleanup' => [
'enabled' => true,
'command' => 'cache:clear',
'parameters' => ['--force'],
],# Enable trigger
php artisan scheduled-trigger:enable test-backup
# Check status
php artisan scheduled-trigger:status
# Disable when done
php artisan scheduled-trigger:disable test-backupNo cron jobs available? Use user traffic to trigger backups:
'tasks' => [
'database-backup' => [
'enabled' => true,
'command' => 'backup:run',
'interval_minutes' => 1440,
'async' => true,
'per_day_limit' => 1,
'retries' => 3,
],
],Combine with UptimeRobot for guaranteed daily backups!
Warm cache when users visit:
'tasks' => [
'cache-warm' => [
'enabled' => true,
'command' => 'route:cache',
'interval_minutes' => 60,
'per_day_limit' => 24,
],
],Generate reports without cron:
'tasks' => [
'daily-report' => [
'enabled' => true,
'command' => 'reports:daily',
'interval_minutes' => 2880, // 48 hours
'per_day_limit' => 1,
],
],- Tasks are only executed in production environment by default
- Lock mechanism prevents race conditions
- Configurable route skipping for sensitive endpoints
- Environment-based access control
Contributions are welcome! Please feel free to submit a Pull Request.
The MIT License (MIT). Please see License File for more information.
Edwin Klesman
- Website: www.eekayonline.com
- Email: online@eekay.nl
- Inspired by the need for scheduled tasks on Digital Ocean App Platform
- Built with β€οΈ for the Laravel community
Please see CHANGELOG for more information on what has changed recently.
Made with β€οΈ by EEKAY ONLINE