PHP code example of azaharizaman / nexus-scheduler

1. Go to this page and download the library: Download azaharizaman/nexus-scheduler library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

azaharizaman / nexus-scheduler example snippets


// app/Repositories/DbScheduleRepository.php
class DbScheduleRepository implements ScheduleRepositoryInterface
{
    public function save(ScheduledJobInterface $job): void { /* ... */ }
    public function findDue(DateTimeImmutable $asOf): array { /* ... */ }
    // ... other methods
}

// app/Services/LaravelJobQueue.php
class LaravelJobQueue implements JobQueueInterface
{
    public function dispatch(ScheduledJobInterface $job, ?int $delaySeconds = null): void
    {
        // Dispatch to Laravel queue
    }
}

// app/Services/SystemClock.php
class SystemClock implements ClockInterface
{
    public function now(): DateTimeImmutable
    {
        return new DateTimeImmutable();
    }
}

// app/Providers/SchedulerServiceProvider.php
public function register(): void
{
    // Bind infrastructure
    $this->app->singleton(ScheduleRepositoryInterface::class, DbScheduleRepository::class);
    $this->app->singleton(JobQueueInterface::class, LaravelJobQueue::class);
    $this->app->singleton(ClockInterface::class, SystemClock::class);
    $this->app->singleton(CalendarExporterInterface::class, NullCalendarExporter::class);
    
    // Inject tagged handlers into ScheduleManager
    $this->app->singleton(ScheduleManager::class, function ($app) {
        return new ScheduleManager(
            repository: $app->make(ScheduleRepositoryInterface::class),
            queue: $app->make(JobQueueInterface::class),
            clock: $app->make(ClockInterface::class),
            handlers: $app->tagged('scheduler.handlers'),
            logger: $app->make(LoggerInterface::class)
        );
    });
}

use Nexus\Scheduler\Services\ScheduleManager;
use Nexus\Scheduler\ValueObjects\ScheduleDefinition;
use Nexus\Scheduler\Enums\JobType;
use Nexus\Scheduler\ValueObjects\ScheduleRecurrence;

$scheduler = app(ScheduleManager::class);

// One-time job
$job = $scheduler->schedule(new ScheduleDefinition(
    jobType: JobType::EXPORT_REPORT,
    targetId: '01JCV9X...',  // ULID of entity
    runAt: new DateTimeImmutable('+1 hour'),
    payload: ['format' => 'pdf', 'templateId' => '01JCV...']
));

// Recurring job (daily at 9 AM)
$job = $scheduler->schedule(new ScheduleDefinition(
    jobType: JobType::DOCUMENT_SHREDDING,
    targetId: '01JCV9Y...',
    runAt: new DateTimeImmutable('tomorrow 09:00'),
    recurrence: new ScheduleRecurrence(
        type: RecurrenceType::DAILY,
        interval: 1
    ),
    payload: ['retentionDays' => 90]
));

// Cron-based recurrence (every Monday at 8 AM)
$job = $scheduler->schedule(new ScheduleDefinition(
    jobType: JobType::WORK_ORDER_START,
    targetId: '01JCV9Z...',
    runAt: new DateTimeImmutable('next Monday 08:00'),
    recurrence: new ScheduleRecurrence(
        type: RecurrenceType::CRON,
        cronExpression: '0 8 * * 1'
    )
));

namespace App\Handlers;

use Nexus\Scheduler\Contracts\JobHandlerInterface;
use Nexus\Scheduler\ValueObjects\ScheduledJob;
use Nexus\Scheduler\ValueObjects\JobResult;
use Nexus\Scheduler\Enums\JobType;

class ExportReportHandler implements JobHandlerInterface
{
    public function __construct(
        private readonly ExportService $exporter
    ) {}
    
    public function supports(JobType $jobType): bool
    {
        return $jobType === JobType::EXPORT_REPORT;
    }
    
    public function handle(ScheduledJob $job): JobResult
    {
        try {
            $this->exporter->generate(
                templateId: $job->payload['templateId'],
                format: $job->payload['format']
            );
            
            return JobResult::success(
                output: ['fileUrl' => 'https://...']
            );
            
        } catch (TemporaryFailureException $e) {
            // Retry with custom 5-minute delay
            return JobResult::failure(
                error: $e->getMessage(),
                shouldRetry: true,
                retryDelaySeconds: 300
            );
            
        } catch (PermanentFailureException $e) {
            // Don't retry
            return JobResult::failure(
                error: $e->getMessage(),
                shouldRetry: false
            );
        }
    }
}

// app/Providers/ExportServiceProvider.php
public function register(): void
{
    // Tag handler for automatic discovery
    $this->app->tag([ExportReportHandler::class], 'scheduler.handlers');
}

// app/Console/Commands/ProcessScheduledJobs.php
public function handle(ScheduleManager $scheduler): int
{
    $dueJobs = $scheduler->getDueJobs();
    
    foreach ($dueJobs as $job) {
        // Dispatches to queue, queue worker invokes handler
        $scheduler->executeJob($job->id);
    }
    
    return 0;
}

return JobResult::failure(
    error: 'API rate limit exceeded',
    shouldRetry: true,
    retryDelaySeconds: 300  // Custom 5-minute delay
);

$job->isDue($clock);           // bool: Is it time to run?
$job->isOverdue($clock);       // bool: Past runAt time?
$job->getNextRunTime($clock);  // ?DateTimeImmutable: Next recurrence
$job->canExecute();            // bool: Is status PENDING?

// Simple interval
new ScheduleRecurrence(
    type: RecurrenceType::DAILY,
    interval: 2  // Every 2 days
);

// Cron expression (

// Success
JobResult::success(output: ['recordsProcessed' => 150]);

// Retriable failure
JobResult::failure(
    error: 'Connection timeout',
    shouldRetry: true,
    retryDelaySeconds: 60
);

// Permanent failure
JobResult::failure(
    error: 'Invalid configuration',
    shouldRetry: false
);

enum JobType: string
{
    case EXPORT_REPORT = 'export_report';
    case DOCUMENT_SHREDDING = 'document_shredding';
    case WORK_ORDER_START = 'work_order_start';
    case SEND_REMINDER = 'send_reminder';
    // Domain packages add their own types
}

enum JobStatus: string
{
    case PENDING = 'pending';
    case RUNNING = 'running';
    case COMPLETED = 'completed';
    case FAILED = 'failed';
    case FAILED_PERMANENT = 'failed_permanent';
    case CANCELED = 'canceled';
    
    public function canTransitionTo(JobStatus $newStatus): bool;
    public function canExecute(): bool;
    public function isFinal(): bool;
}

$mockClock = new class implements ClockInterface {
    private DateTimeImmutable $now;
    
    public function now(): DateTimeImmutable {
        return $this->now;
    }
    
    public function setTime(DateTimeImmutable $time): void {
        $this->now = $time;
    }
};

// Test isDue() logic
$mockClock->setTime(new DateTimeImmutable('2025-01-15 08:55:00'));
$this->assertFalse($job->isDue($mockClock));

$mockClock->setTime(new DateTimeImmutable('2025-01-15 09:00:00'));
$this->assertTrue($job->isDue($mockClock));

* * * * * php artisan schedule:process