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

Cron Job Laravel Package

becklyn/cron-job

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require becklyn/cron-job-bundle
    

    Add to config/bundles.php:

    return [
        // ...
        Becklyn\CronJobBundle\CronJobBundle::class => ['all' => true],
    ];
    
  2. First Job Definition Create a job class in src/Command/ (or any directory):

    namespace App\Command;
    
    use Becklyn\CronJobBundle\Job\JobInterface;
    use Symfony\Component\Console\Command\Command;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Output\OutputInterface;
    
    class MyFirstJob extends Command implements JobInterface
    {
        protected static $defaultName = 'app:my-first-job';
    
        public function run(InputInterface $input, OutputInterface $output): int
        {
            $output->writeln('Running my first cron job!');
            return Command::SUCCESS;
        }
    
        public function getSchedule(): string
        {
            return '* * * * *'; // Every minute
        }
    }
    
  3. Enable the Job Add to config/packages/becklyn_cron_job.yaml:

    jobs:
        app.my_first_job: ~
    
  4. Run the Scheduler

    php bin/console becklyn:cron-job:run
    

    (For production, set up a system cron to run this command periodically.)


First Use Case: Logging System Events

Define a job to log system events nightly:

class NightlySystemLogJob extends Command implements JobInterface
{
    public function run(InputInterface $input, OutputInterface $output): int
    {
        $logger = $this->getLogger();
        $logger->info('Nightly system log entry', [
            'timestamp' => (new \DateTime())->format('Y-m-d H:i:s'),
            'event' => 'system_health_check'
        ]);
        return Command::SUCCESS;
    }

    public function getSchedule(): string
    {
        return '0 3 * * *'; // 3 AM daily
    }
}

Implementation Patterns

1. Job Organization

  • Group Jobs by Domain:
    src/
    ├── Command/
    │   ├── User/
    │   │   ├── SyncUserDataJob.php
    │   │   └── CleanupInactiveUsersJob.php
    │   ├── System/
    │   │   └── MaintenanceLogJob.php
    │   └── ...
    
  • Use Traits for Shared Logic:
    trait LoggableJob
    {
        protected function logExecution(string $message): void
        {
            $this->getLogger()->info($message, ['job' => static::class]);
        }
    }
    

2. Dependency Injection

  • Inject services into jobs via constructor:
    use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
    
    #[AutoconfigureTag('cron_job')]
    class SyncUserDataJob extends Command implements JobInterface
    {
        public function __construct(
            private UserRepository $userRepository,
            private MailerInterface $mailer
        ) {}
    
        public function run(InputInterface $input, OutputInterface $output): int
        {
            $users = $this->userRepository->findPendingSync();
            foreach ($users as $user) {
                $this->mailer->sendSyncNotification($user);
            }
            return Command::SUCCESS;
        }
    }
    

3. Dynamic Scheduling

  • Use environment variables for schedules:
    # .env
    CRON_JOB_SYNC_USERS_SCHEDULE="0 0 * * 1" # Every Monday at midnight
    
    public function getSchedule(): string
    {
        return $_ENV['CRON_JOB_SYNC_USERS_SCHEDULE'] ?? '* * * * *';
    }
    

4. Job Chaining

  • Trigger jobs sequentially or conditionally:
    public function run(InputInterface $input, OutputInterface $output): int
    {
        $this->runJob(new BackupDatabaseJob());
        if ($this->shouldSendReport()) {
            $this->runJob(new SendWeeklyReportJob());
        }
        return Command::SUCCESS;
    }
    
    private function runJob(JobInterface $job): void
    {
        $job->run(new ArrayInput([]), new NullOutput());
    }
    

5. Event-Driven Jobs

  • Dispatch Symfony events from jobs:
    use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
    
    public function __construct(private EventDispatcherInterface $dispatcher) {}
    
    public function run(InputInterface $input, OutputInterface $output): int
    {
        $this->dispatcher->dispatch(new JobExecutedEvent(static::class));
        return Command::SUCCESS;
    }
    

6. Configuration Management

  • Centralize job configs in YAML:
    # config/packages/becklyn_cron_job.yaml
    jobs:
        app.user_sync:
            schedule: "0 2 * * *" # Daily at 2 AM
            enabled: true
            timeout: 3600 # 1 hour
        app.cleanup_temp_files:
            schedule: "0 1 * * *" # Daily at 1 AM
            enabled: "%env(bool:CRON_JOB_CLEANUP_ENABLED)%"
    

Gotchas and Tips

Pitfalls

  1. Schedule Parsing Errors

    • Cron expressions are case-sensitive and must follow UNIX cron syntax.
    • Fix: Validate schedules with Cron\CronExpression:
      use Cron\CronExpression;
      
      public function getSchedule(): string
      {
          $schedule = '* * * * *';
          if (!CronExpression::isValid($schedule)) {
              throw new \RuntimeException("Invalid cron schedule: {$schedule}");
          }
          return $schedule;
      }
      
  2. Job Registration Order

    • Jobs must be autowired or manually registered in the container.
    • Fix: Ensure jobs are tagged with cron_job:
      #[AutoconfigureTag('cron_job')]
      class MyJob extends Command implements JobInterface {}
      
      Or register manually in services.yaml:
      services:
          App\Command\MyJob:
              tags: ['cron_job']
      
  3. Output Handling

    • Jobs run silently by default. Use OutputInterface to log progress.
    • Tip: Redirect output to a file:
      $output->writeln('Processing...');
      $output->to($this->getOutputFile());
      
  4. Long-Running Jobs

    • Jobs run in the same process as the scheduler. Avoid blocking calls.
    • Fix: Use setTimeout() in Symfony 5.3+ or run heavy tasks asynchronously:
      $this->getContainer()->get('messenger')->dispatch(
          new ProcessHeavyTaskMessage($data)
      );
      
  5. Time Zone Issues

    • Cron schedules use the server’s time zone. Explicitly set it if needed:
      use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
      
      #[AutoconfigureTag('cron_job')]
      class TimeZoneAwareJob extends Command implements JobInterface
      {
          public function __construct(private \DateTimeZone $timeZone) {}
      
          public function getSchedule(): string
          {
              return '@daily'; // Uses the configured time zone
          }
      }
      

Debugging Tips

  1. Dry Run Mode Enable logging to preview jobs:

    # config/packages/becklyn_cron_job.yaml
    debug: true
    

    Outputs scheduled jobs to var/log/dev.log.

  2. Manual Job Execution Test jobs without waiting for the cron:

    php bin/console app:my_job
    
  3. Job Execution Logs Use Symfony’s logger to track runs:

    public function run(InputInterface $input, OutputInterface $output): int
    {
        $this->logger->info('Job started', ['job' => static::class]);
        try {
            // Job logic
            $this->logger->info('Job completed successfully');
        } catch (\Throwable $e) {
            $this->logger->error('Job failed', ['exception' => $e->getMessage()]);
            throw $e;
        }
        return Command::SUCCESS;
    }
    

Extension Points

  1. Custom Job Storage Override the job repository to store schedules in a database:
    use Becklyn\CronJobBundle\Repository\JobRepositoryInterface;
    
    class DatabaseJobRepository implements JobRepositoryInterface
    {
        public function findAll(): array
        {
            return $this->entityManager->getRepository(Job::class)->findAll();
        }
    }
    
    Bind it in services.yaml:
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui