Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Laravel Scheduler

A Laravel application for running scheduled tasks safely across one or more servers. It uses Redis locks to prevent duplicate and overlapping runs.

The project includes one example task: system.scheduler-heartbeat. It runs every five minutes and writes a heartbeat to the database.

Technology

  • PHP 8.4.1 or newer (Docker uses PHP 8.5)
  • Laravel 13
  • Redis 8 with PhpRedis
  • SQLite
  • Node.js 22 and Vite
  • Docker Compose

Installation

You need Git, Docker, and Docker Compose.

git clone https://github.com/janmikolas/scheduling.git
cd scheduling
make up

The first start may take a moment. Docker installs the dependencies, creates .env and the SQLite database, generates the application key, and runs the migrations.

The application is then available at:

Check the scheduler:

docker compose exec app php artisan scheduler:diagnose
docker compose exec app php artisan scheduler:tasks

Stop the project with:

make down

Architecture

The code is organized by module. Each module may contain four layers:

Layer Purpose
Domain Business rules and value objects
Application Classes that perform the application's work
Infrastructure Laravel, database, Redis, and other integrations
UI HTTP controllers, requests, and responses

Domain and Application code do not depend on Laravel.

app/
├── Shared/Scheduling/  # Scheduler, task contracts, and Redis locks
└── System/             # Scheduler heartbeat example

A scheduled task passes through the application like this:

Laravel Scheduler / manual invocation
    → scheduler:run-task <task-id>
    → occurrence lock
    → execution lock
    → module task
    → Application class

Schedules use Europe/Prague. Technical timestamps are stored in UTC. If Redis is unavailable, the task is not started because its locks cannot be checked safely.

Adding a scheduled task

Use SchedulerHeartbeatTask as a template.

1. Create the task

Place it in the module's Infrastructure/Scheduling directory and implement ScheduledTask.

The definition controls when and where the task runs:

public function definition(): ScheduledTaskDefinition
{
    return new ScheduledTaskDefinition(
        id: ScheduledTaskId::fromString('reports.daily-report'),
        description: ScheduledTaskDescription::fromString(
            'Generates the daily report',
        ),
        cron: CronExpression::fromString('0 6 * * *'),
        overlapPolicy: OverlapPolicy::preventFor(
            LockTtl::minutes(30),
        ),
        executionScope: ExecutionScope::SingleSchedulerNode,
        enabled: true,
    );
}

The execute() method should only call the class that performs the work:

public function execute(ScheduledTaskContext $context): void
{
    $this->generateDailyReport->execute();
}

2. Register the task

Add it to the module's Laravel service provider:

$this->app->singleton(DailyReportTask::class);
$this->app->tag(
    [DailyReportTask::class],
    'application.scheduled-task',
);

Register a new module service provider in bootstrap/providers.php.

3. Verify it

docker compose exec app php artisan scheduler:tasks
docker compose exec app php artisan schedule:list
docker compose exec app php artisan scheduler:run-task reports.daily-report

Commands

Development

Command Purpose
make up Build and start all services
make down Stop all services
make php Open a shell in the PHP container

Tests and code quality

Command Purpose
make test Run all tests with Laravel
make phpunit Run PHPUnit directly
make coverage Generate HTML test coverage
make phpstan Run static analysis
make phpcs / make phpcsfix Check or fix PHP_CodeSniffer rules
make phpecs / make phpecsfix Check or fix Easy Coding Standard rules
make deptrac Check architecture dependencies

Run a single test suite or file:

docker compose exec app php artisan test --testsuite=Unit
docker compose exec app php artisan test tests/Feature/HealthEndpointTest.php

Scheduler

Command Purpose
php artisan scheduler:tasks List registered tasks
php artisan schedule:list Show the schedule and next run times
php artisan scheduler:run-task <task-id> Run one task immediately
php artisan scheduler:diagnose Check scheduler health
php artisan scheduler:mutex:inspect <task-id> --kind=execution Inspect a task lock

Run Artisan commands in Docker with:

docker compose exec app php artisan <command>

Configuration

Scheduler settings are stored in config/scheduling.php. The main environment variables are:

Variable Default
SCHEDULER_TIMEZONE Europe/Prague
SCHEDULER_LOCK_PREFIX scheduler-service:scheduler:
SCHEDULER_OCCURRENCE_TTL_SECONDS 10800
SCHEDULER_REDIS_HOST 127.0.0.1
SCHEDULER_REDIS_PORT 6379
SCHEDULER_REDIS_DB 2

See .env.example for the complete configuration.

Documentation

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages