Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Cronless Schedule Laravel Package

spatie/laravel-cronless-schedule

Run Laravel’s scheduler without cron. This dev/test-friendly package adds php artisan schedule:run-cronless, which uses a ReactPHP loop to execute the scheduler on a timer (default every minute), with optional custom frequency and manual runs.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require spatie/laravel-cronless-schedule
    

    Publish the config (optional):

    php artisan vendor:publish --provider="Spatie\CronlessSchedule\CronlessScheduleServiceProvider"
    
  2. First Use Case: Run the scheduler locally without cron:

    php artisan schedule:run-cronless
    
    • This command runs indefinitely, simulating a cron job every minute using ReactPHP.
    • Ideal for local development, testing, or environments where cron is unavailable (e.g., Docker, CI/CD pipelines).
  3. Where to Look First:

    • README for basic usage.
    • config/cronless-schedule.php for customization (e.g., interval, logging).
    • app/Console/Kernel.php to define your scheduled tasks (standard Laravel scheduler syntax).

Implementation Patterns

Core Workflows

  1. Local Development:

    • Replace cron with php artisan schedule:run-cronless in your package.json scripts or .env:
      "scripts": {
        "dev": "php artisan schedule:run-cronless & npm run dev"
      }
      
    • Pro Tip: Use nohup or tmux to keep the process running in the background:
      nohup php artisan schedule:run-cronless > cronless.log 2>&1 &
      
  2. Testing:

    • Mock the scheduler in PHPUnit tests using Spatie\CronlessSchedule\Testing\CronlessSchedule:
      use Spatie\CronlessSchedule\Testing\CronlessSchedule;
      
      public function test_scheduled_job()
      {
          CronlessSchedule::run();
      
          $this->assertDatabaseHas('jobs', ['status' => 'completed']);
      }
      
    • Run tests with the scheduler active:
      php artisan schedule:run-cronless --once  # Runs once and exits (for testing)
      
  3. Integration with CI/CD:

    • Use in GitHub Actions or GitLab CI to test scheduled jobs:
      # .github/workflows/test.yml
      jobs:
        test:
          runs-on: ubuntu-latest
          steps:
            - run: php artisan schedule:run-cronless --once
            - run: php artisan test
      
  4. Custom Intervals:

    • Override the default 1-minute interval via config:
      // config/cronless-schedule.php
      'interval' => 30, // Runs every 30 seconds
      

Advanced Patterns

  1. Logging:

    • Enable verbose logging to debug issues:
      php artisan schedule:run-cronless --verbose
      
    • Or configure logging in config/cronless-schedule.php:
      'log' => [
          'enabled' => true,
          'channel' => 'single',
      ],
      
  2. Environment-Specific Setup:

    • Use .env to toggle cronless mode:
      CRONLESS_SCHEDULE_ENABLED=true
      
    • Add a helper to app/Console/Kernel.php:
      protected function schedule(Schedule $schedule)
      {
          if (env('CRONLESS_SCHEDULE_ENABLED')) {
              $schedule->command('schedule:run-cronless')->everyMinute();
          }
      }
      
  3. Docker/Containerized Environments:

    • Run as a detached service in docker-compose.yml:
      services:
        app:
          command: php artisan schedule:run-cronless
          restart: unless-stopped
      

Gotchas and Tips

Pitfalls

  1. Blocking the Process:

    • schedule:run-cronless runs forever by default. Avoid running it in production unless you’re using a process manager (e.g., Supervisor) to manage it.
    • Fix: Use --once for testing or wrap it in a process manager.
  2. ReactPHP Dependencies:

    • The package uses ReactPHP, which may conflict with other async libraries (e.g., Laravel Echo, Horizon).
    • Fix: Ensure no other ReactPHP loops are running concurrently.
  3. Timezone Mismatches:

    • Scheduled jobs use the server’s timezone. If your local machine’s timezone differs from production, jobs may run at unexpected times.
    • Fix: Set a consistent timezone in .env:
      APP_TIMEZONE=UTC
      
  4. Database Locks:

    • Running the scheduler in a loop can cause database lock timeouts if jobs are slow or stuck.
    • Fix: Optimize long-running jobs or increase DB_CONNECTION_TIMEOUT.
  5. Missing schedule:run Command:

    • If you forget to define jobs in app/Console/Kernel.php, the cronless scheduler will do nothing.
    • Fix: Always include:
      $schedule->command('your:command')->everyMinute();
      

Debugging Tips

  1. Check Logs:

    • Enable logging in config/cronless-schedule.php and check storage/logs/laravel.log for errors.
  2. Simulate Failures:

    • Force a job to fail in tests to verify error handling:
      CronlessSchedule::run();
      $this->expectException(JobFailureException::class);
      
  3. Inspect ReactPHP Loop:

    • Use --verbose to see the loop’s activity:
      php artisan schedule:run-cronless --verbose
      

Extension Points

  1. Custom Commands:

    • Extend the scheduler to run additional commands:
      // app/Console/Kernel.php
      protected function schedule(Schedule $schedule)
      {
          $schedule->command('analytics:refresh')->hourly();
          $schedule->command('cache:clear')->daily();
      }
      
  2. Event Listeners:

    • Listen for scheduler events (e.g., job started/failed):
      use Spatie\CronlessSchedule\Events\JobExecuted;
      
      Event::listen(JobExecuted::class, function ($event) {
          Log::info("Job '{$event->job}' executed at {$event->time}");
      });
      
  3. Custom Interval Logic:

    • Override the interval dynamically (e.g., based on environment):
      // config/cronless-schedule.php
      'interval' => function () {
          return env('FAST_SCHEDULE') ? 10 : 60; // 10s or 1m
      },
      
  4. Integration with Laravel Forge/Laravel Vapor:

    • Use the package in Forge/Vapor for local testing, but rely on their native cron in production.

Config Quirks

  1. Default Config:

    • The package ships with sensible defaults (1-minute interval, no logging). Always check config/cronless-schedule.php before assuming behavior.
  2. Environment Variables:

    • The interval can be set via .env:
      CRONLESS_SCHEDULE_INTERVAL=30
      
  3. Process Management:

    • If using Supervisor, configure it to restart the process on failure:
      [program:scheduler]
      command=php /path/to/artisan schedule:run-cronless
      autorestart=true
      user=www-data
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport