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

Scheduler Bundle Laravel Package

aboutcoders/scheduler-bundle

Symfony bundle for defining recurring schedules and dispatching notifications via the Symfony EventDispatcher. Designed to be integrated into your app by implementing your own schedule entities, with docs for installation, configuration, and custom schedule types.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require aboutcoders/scheduler-bundle
    

    Enable the bundle in config/bundles.php:

    Aboutcoders\SchedulerBundle\AboutcodersSchedulerBundle::class => ['all' => true],
    
  2. First Use Case: Define a schedule entity (e.g., App\Entity\MySchedule) extending Aboutcoders\SchedulerBundle\Entity\AbstractSchedule:

    use Aboutcoders\SchedulerBundle\Entity\AbstractSchedule;
    use Doctrine\ORM\Mapping as ORM;
    
    #[ORM\Entity]
    class MySchedule extends AbstractSchedule
    {
        // Custom fields (e.g., cron expression, event name)
        #[ORM\Column(type: 'string')]
        private string $eventName;
    
        // Getters/setters...
    }
    
  3. Dispatch Events: Configure a listener to trigger actions when schedules run:

    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Aboutcoders\SchedulerBundle\Event\ScheduleEvent;
    
    class MyScheduleSubscriber implements EventSubscriberInterface
    {
        public static function getSubscribedEvents(): array
        {
            return [
                'my.schedule.event' => 'onScheduleRun',
            ];
        }
    
        public function onScheduleRun(ScheduleEvent $event)
        {
            // Handle logic (e.g., send email, update DB)
        }
    }
    
  4. Run the Scheduler: Add a cron job to execute the scheduler command:

    php bin/console aboutcoders:scheduler:run
    

    Schedule it (e.g., every minute):

    * * * * * /path/to/php bin/console aboutcoders:scheduler:run >> /dev/null 2>&1
    

Implementation Patterns

Core Workflows

  1. Schedule Definition:

    • Extend AbstractSchedule for custom schedules.
    • Use annotations (e.g., @Cron) or fields (e.g., cronExpression) to define recurrence.
    • Example:
      #[ORM\Entity]
      class DailyReportSchedule extends AbstractSchedule
      {
          #[ORM\Column(type: 'string')]
          private string $cronExpression = '0 0 * * *'; // Daily at midnight
      }
      
  2. Event-Driven Actions:

    • Dispatch events in ScheduleEvent listeners for side effects (e.g., notifications, API calls).
    • Example:
      public function onScheduleRun(ScheduleEvent $event)
      {
          $schedule = $event->getSchedule();
          $this->mailer->send(new Email($schedule->getEventName()));
      }
      
  3. Integration with Jobs:

    • Pair with aboutcoders/job-bundle to queue delayed tasks:
      use Aboutcoders\JobBundle\Job\JobInterface;
      
      class SendReportJob implements JobInterface
      {
          public function run(): void
          {
              // Send report logic
          }
      }
      
    • Attach jobs to schedules via listeners.
  4. Dynamic Scheduling:

    • Use ScheduleManager to create/update schedules programmatically:
      $schedule = $this->scheduleManager->create(
          MySchedule::class,
          ['eventName' => 'user.activation']
      );
      $schedule->setCronExpression('0 9 * * *'); // 9 AM daily
      $this->entityManager->persist($schedule);
      

Best Practices

  • Granularity: Use short cron expressions (e.g., */5 * * * * for every 5 minutes) to balance precision and load.
  • Idempotency: Design listeners to handle duplicate events (e.g., retries).
  • Logging: Log schedule runs for debugging:
    $this->logger->info('Schedule run', ['schedule' => $schedule->getId()]);
    

Gotchas and Tips

Common Pitfalls

  1. Cron Syntax Errors:

    • Invalid cron expressions (e.g., 0 25 * * * for 25:00) will silently fail. Validate with:
      use Cron\CronExpression;
      $expr = CronExpression::factory($schedule->getCronExpression());
      
    • Use crontab.guru to test expressions.
  2. Missing Doctrine Entities:

    • Forgetting to register the schedule entity with Doctrine or Symfony’s autowiring will cause NoSuchEntityException.
    • Verify with:
      php bin/console doctrine:schema:validate
      
  3. Event Dispatcher Misconfiguration:

    • Events must match the eventName field in the schedule entity. Typos here will make schedules appear "invisible."
    • Debug with:
      php bin/console debug:event-dispatcher
      
  4. Time Zone Issues:

    • Cron expressions use the server’s time zone. Explicitly set time zones in schedules if needed:
      $schedule->setTimezone(new \DateTimeZone('America/New_York'));
      

Debugging Tips

  • Check Last Run: Query the schedules table for last_run_at and next_run_at to verify timing.
  • Enable Debug Mode: Set debug: true in config/packages/aboutcoders_scheduler.yaml to log skipped schedules.
  • Manual Trigger: Test schedules manually with:
    php bin/console aboutcoders:scheduler:run --dry-run
    

Extension Points

  1. Custom Schedule Types:

    • Implement Aboutcoders\SchedulerBundle\Schedule\ScheduleInterface for non-cron schedules (e.g., "run every 3 hours").
    • Register via services.yaml:
      services:
          App\Schedule\CustomSchedule:
              tags:
                  - { name: aboutcoders_scheduler.schedule_type, type: custom }
      
  2. Pre/Post Hooks:

    • Extend AbstractSchedule to add lifecycle methods (e.g., onBeforeRun(), onAfterRun()).
  3. Conditional Execution:

    • Use listeners to skip runs based on business logic:
      if (!$this->isValidDay($event->getSchedule()->getCreatedAt())) {
          return;
      }
      

Configuration Quirks

  • Default Cron: If cronExpression is empty, the schedule won’t run. Always set a default.
  • Overlapping Runs: The bundle doesn’t handle overlapping runs by default. Use locks (e.g., symfony/lock) if needed:
    use Symfony\Component\Lock\LockFactory;
    
    $lock = $this->lockFactory->createLock('my_schedule_lock', 300);
    if (!$lock->acquire()) {
        return; // Skip if another run is in progress
    }
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky