PHPackages                             zachiler/laravel-cadence - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. zachiler/laravel-cadence

ActiveLibrary[Testing &amp; Quality](/categories/testing)

zachiler/laravel-cadence
========================

Run your Laravel application in accelerated time with a tick-based simulation loop.

v0.1.1-alpha(1mo ago)013MITPHPPHP ^8.2CI passing

Since Mar 15Pushed 1mo agoCompare

[ Source](https://github.com/zachiler/laravel-cadence)[ Packagist](https://packagist.org/packages/zachiler/laravel-cadence)[ RSS](/packages/zachiler-laravel-cadence/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (8)Versions (4)Used By (0)

Laravel Cadence
===============

[](#laravel-cadence)

Run your Laravel application in accelerated time.

[![Tests](https://github.com/zachiler/laravel-cadence/actions/workflows/tests.yml/badge.svg)](https://github.com/zachiler/laravel-cadence/actions/workflows/tests.yml)[![PHP Version](https://camo.githubusercontent.com/7e80c5a44b0f819258f09384c7af693fe7f3f1ebe4ae8c6833b5c34f2dd57d03/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344382e332d3838393242462e737667)](https://www.php.net/)[![Laravel Version](https://camo.githubusercontent.com/7aed3dbb1a1293fd5f136ad1d1ae9a68c4ba2cd77a058e81bfb7cc2ecbf76851/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d25334525334431322e302d4646324432302e737667)](https://laravel.com/)[![License](https://camo.githubusercontent.com/074b89bca64d3edc93a1db6c7e3b1636b874540ba91d66367c0e5e354c56d0ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e737667)](LICENSE)

What It Does
------------

[](#what-it-does)

Install the package, implement a tick handler, and run `cadence:run`. Your Eloquent models, queued jobs, and scheduled commands all operate against simulated time — hours pass in seconds. Observe your application behaving as if days or weeks have elapsed, all from a single Artisan command.

Quick Start
-----------

[](#quick-start)

```
composer require zachiler/laravel-cadence
php artisan cadence:install
php artisan migrate
```

```
// app/Cadence/Handlers/OrderHandler.php
class OrderHandler extends \Cadence\Support\BaseHandler
{
    protected function handle(\Cadence\State\TickContext $context): void
    {
        $context->businessHours()->every('1 hour', 'create-orders', function () {
            Order::factory()->count($this->config('order_rate', 3))->create();
        });
    }
}
```

```
php artisan cadence:run --scenario=growth --duration="14 days"
```

Register your scenario in `config/cadence.php`:

```
'scenarios' => [
    'growth' => App\Cadence\Scenarios\GrowthScenario::class,
],
```

See [Getting Started](docs/getting-started.md) for the full walkthrough.

Configuration
-------------

[](#configuration)

```
// config/cadence.php
return [
    // Environments where Cadence is allowed to run.
    'allowed_environments' => ['local', 'staging'],

    // Default simulation settings. Can be overridden per-run via CLI options.
    'defaults' => [
        // Simulated seconds per real second. 900 = 15 simulated minutes per real second.
        'speed' => 900,

        // Real-time interval between ticks in milliseconds.
        'tick_interval' => 1000,
    ],

    // Named presets for common simulation profiles.
    // Usage: php artisan cadence:run --preset=fast
    'presets' => [
        'fast' => ['speed' => 7200, 'tick_interval' => 500],
        'slow' => ['speed' => 300, 'tick_interval' => 2000],
        'realtime' => ['speed' => 1, 'tick_interval' => 1000],
    ],

    // Queue connection during simulation. Must be 'database'.
    'queue_connection' => 'database',

    // Where database snapshots are stored.
    'snapshot_path' => storage_path('cadence/snapshots'),

    // Custom binary paths for snapshot commands (null = auto-detect).
    'binary_paths' => [
        'mysqldump' => null,
        'mysql' => null,
        'pg_dump' => null,
        'psql' => null,
    ],

    // Prefix for all cache keys used for cross-process state.
    'cache_prefix' => 'cadence',

    // Cache store for simulation state and signals. null = app default.
    'state_store' => null,

    // Named scenarios (implement Cadence\Contracts\Scenario).
    // Supports class strings or [class, default_params] arrays.
    'scenarios' => [
        // 'growth' => App\Cadence\Scenarios\GrowthScenario::class,
        // 'growth-aggressive' => ['class' => App\Cadence\Scenarios\GrowthScenario::class, 'params' => ['signup_rate' => 0.9]],
    ],

    // Tick handler classes (used when no --scenario is specified).
    'handlers' => [],

    // Default options passed to handler config.
    'handler_options' => [],

    // Maximum real-time seconds a single tick is allowed to take. 0 = no limit.
    'max_tick_duration' => 30,

    // Event log storage driver: 'database' or 'file'.
    'event_log_driver' => 'database',

    // Path for JSONL event log when using the 'file' driver.
    'event_log_path' => storage_path('cadence/events.jsonl'),
];
```

How Time Works
--------------

[](#how-time-works)

Cadence uses Carbon's `setTestNow()` to shift all time-dependent code. During a simulation:

- **`now()`, `Carbon::now()`, `Date::now()`** — all return simulated time
- **Eloquent timestamps** (`created_at`, `updated_at`) — use simulated time automatically
- **Queued job delays** — evaluated against simulated time
- **Scheduled commands** — fire based on simulated cron evaluation

You do not need to call any special clock function in your application code. Standard Laravel time functions work as expected — the simulation makes them return simulated time instead of real time.

The `Clock` class (`Cadence\Clock\Clock`) is used internally by the runner. You can use `Clock::now()` or just `now()` — they return the same value during simulation.

Feature Highlights
------------------

[](#feature-highlights)

### Tick Scheduling DSL

[](#tick-scheduling-dsl)

Avoid time-checking boilerplate. The DSL handles interval tracking and day/time filtering:

```
$context->businessHours()->every('1 hour', 'process-orders', function () { /* ... */ });
$context->weekends()->every('4 hours', 'weekend-report', function () { /* ... */ });
$context->on('monday')->between('09:00', '12:00')->every('30 minutes', 'standup', function () { /* ... */ });
```

[Full reference](docs/tick-scheduling.md)

### Handler Dependencies

[](#handler-dependencies)

Declare execution order through dependencies — the runner topologically sorts handlers before the first tick:

```
class BillingHandler extends BaseHandler implements HasHandlerDependencies
{
    public function dependsOn(): array
    {
        return [TeamLifecycleHandler::class, ProjectActivityHandler::class];
    }
}
```

[Full reference](docs/handler-dependencies.md)

### Invariants &amp; Breakpoints

[](#invariants--breakpoints)

Define conditions checked after every tick. Invariants assert correctness; breakpoints pause for inspection:

```
$runner->invariant(fn () => User::count() > 0, 'has-users', InvariantBehavior::Pause);
$runner->breakWhen(fn () => Order::where('status', 'failed')->count() > 10, 'too-many-failures');
```

[Full reference](docs/invariants-breakpoints.md)

### Time-Series Metrics

[](#time-series-metrics)

Record named metrics from handlers for post-run analysis:

```
$this->metric('teams.active', Team::count());     // gauge
$this->increment('invoices.created', $count);      // counter
$series = MetricQuery::series('teams.active');      // query after run
```

[Full reference](docs/telemetry-metrics.md)

### Speed Schedules

[](#speed-schedules)

Define multi-phase speed profiles for a single run:

```
$runner->speedSchedule([
    ['until' => '7 days', 'speed' => 3600],
    ['until' => 'end',    'speed' => 60],
]);
```

[Full reference](docs/speed-control.md)

### Tick Middleware

[](#tick-middleware)

Wrap the entire tick cycle with before/after logic:

```
class LogTickDuration implements TickMiddleware
{
    public function handle(TickContext $context, \Closure $next): void
    {
        $start = microtime(true);
        $next($context);
        logger("Tick {$context->tick} took " . round(microtime(true) - $start, 3) . 's');
    }
}
```

[Full reference](docs/middleware.md)

### Simulation Report

[](#simulation-report)

An automatic end-of-run summary with handler performance, event counts, and telemetry:

```
╔══════════════════════════════════════════╗
║     Cadence Simulation Summary           ║
╚══════════════════════════════════════════╝

  Scenario: growth
  Ticks: 168
  Speed: 3600x
  Reason: completed
  Real elapsed: 187.4s
  Events logged: 1,247

  Handler Performance
+------------------------+-------+---------+----------+----------+
| Handler                | Ticks | Elapsed | Avg (ms) | P95 (ms) |
+------------------------+-------+---------+----------+----------+
| TeamLifecycleHandler   | 168   | 187.4s  | 22.31    | 189.42   |
| ProjectActivityHandler | 168   | 185.2s  | 1.24     | 5.87     |
| BillingHandler         | 168   | 185.3s  | 2.14     | 3.21     |
| EscalationHandler      | 168   | 185.3s  | 0.58     | 1.12     |
+------------------------+-------+---------+----------+----------+

```

[Full reference](docs/simulation-lifecycle.md)

### And More...

[](#and-more)

- [Warm-up periods](docs/simulation-lifecycle.md) — Separate bootstrap noise from measured results
- [Simulation tagging](docs/simulation-lifecycle.md) — Attach metadata for filtering and comparison
- [Auto-checkpoints](docs/snapshots.md) — Automatic snapshots at simulated time intervals
- [Handler telemetry](docs/telemetry-metrics.md) — Automatic min/max/avg/p95 timing per handler
- [Config hot-reload](docs/handler-communication.md) — Update handler config mid-simulation
- [Quiet period skipping](docs/speed-control.md) — Fast-forward through inactive periods
- [Adaptive speed](docs/speed-control.md) — Slow ticks run at 1:1 real time automatically
- [Snapshot metadata hooks](docs/snapshots.md) — Attach custom data to database snapshots
- [Handler communication (TickBag)](docs/handler-communication.md) — Share data between handlers within a tick
- [Clock-aware Eloquent scopes](docs/eloquent-scopes.md) — Time-window queries that respect simulated time
- [Dry-run mode](docs/simulation-lifecycle.md) — Preview without persisting data
- [Reproducible simulations](docs/simulation-lifecycle.md) — Deterministic Faker output with `--seed`

Documentation
-------------

[](#documentation)

TopicDescription[Getting Started](docs/getting-started.md)Installation, first handler, first run[Handlers](docs/handlers.md)TickHandler, BaseHandler, config, logging, TickContext API[Scenarios](docs/scenarios.md)Scenario interface, parameters, registration[Tick Scheduling](docs/tick-scheduling.md)The DSL: every(), businessHours(), weekdays(), between(), on()[Running Simulations](docs/running-simulations.md)CLI options, presets, controlling, monitoring[Handler Dependencies](docs/handler-dependencies.md)Dependency declarations, topological sort, exceptions[Invariants &amp; Breakpoints](docs/invariants-breakpoints.md)Assertions, pause/throw/log behaviors, breakpoints[Middleware](docs/middleware.md)Tick middleware, before/after pattern, short-circuiting[Telemetry &amp; Metrics](docs/telemetry-metrics.md)Handler performance, time-series metrics, MetricQuery[Speed Control](docs/speed-control.md)Speed schedules, adaptive speed, quiet period skipping[Snapshots](docs/snapshots.md)Taking, restoring, metadata hooks, auto-checkpoints[Simulation Lifecycle](docs/simulation-lifecycle.md)Warm-up, tagging, dry-run, reproducibility, report[Handler Communication](docs/handler-communication.md)TickBag, config hot-reload[Event Logging](docs/event-logging.md)Writing, querying, exporting, streaming, CadenceEventType[Eloquent Scopes](docs/eloquent-scopes.md)Clock-aware createdSince, updatedSince, between scopes[Database Drivers](docs/database-drivers.md)MySQL/PG vs SQLite, cache driver selection[Testing](docs/testing.md)TickContext::factory(), handler testing patternsRequirements
------------

[](#requirements)

- PHP 8.3+
- Laravel 12+
- MySQL or PostgreSQL recommended (see [Database Drivers](docs/database-drivers.md))
- Database queue driver (during simulation only)
- Cross-process cache driver (file, database, Redis, or Memcached)

Database Drivers
----------------

[](#database-drivers)

MySQL and PostgreSQL are recommended. SQLite works for quick local tests but causes lock contention under real simulation loads. See [Database Drivers](docs/database-drivers.md) for configuration details and workarounds.

Safety
------

[](#safety)

- **Environment gating** — `cadence:run` refuses to execute in environments not listed in `allowed_environments`
- **Concurrent run prevention** — checks for an already-running simulation before starting
- **Queue driver enforcement** — validates `QUEUE_CONNECTION=database` at runtime
- **Cache driver validation** — rejects `array` and `null` cache drivers that can't communicate across processes
- **Tick timeout** — `max_tick_duration` prevents a single tick from blocking the simulation indefinitely
- **Clock cleanup** — `setTestNow` is always reset in a `finally` block, even on crash
- **Snapshot confirmation** — `cadence:restore` requires interactive confirmation before replacing the database
- **Dependency validation** — circular and missing handler dependencies are caught at boot, not mid-simulation
- **Dry-run isolation** — `--dry-run` wraps the entire simulation in a transaction, rolling back all data changes

About
-----

[](#about)

Laravel Cadence was co-authored by [Zac Hiler](https://zachiler.dev) and [Claude](https://claude.ai). Learn more about the journey of building Laravel Cadence at [zachiler.dev/projects/laravel-cadence](https://zachiler.dev/projects/laravel-cadence).

License
-------

[](#license)

MIT. See [LICENSE](LICENSE).

###  Health Score

36

—

LowBetter than 82% of packages

Maintenance88

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity34

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

58d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/5ebaadd57174c253723a60d2f403a600ed2cb2ff8c4b2dc37039eab5be4b1386?d=identicon)[zachiler](/maintainers/zachiler)

---

Top Contributors

[![zachiler](https://avatars.githubusercontent.com/u/79065463?v=4)](https://github.com/zachiler "zachiler (4 commits)")

---

Tags

testinglaraveltimedemosimulation

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/zachiler-laravel-cadence/health.svg)

```
[![Health](https://phpackages.com/badges/zachiler-laravel-cadence/health.svg)](https://phpackages.com/packages/zachiler-laravel-cadence)
```

###  Alternatives

[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k43.5M5.2k](/packages/larastan-larastan)[laravel/horizon

Dashboard and code-driven configuration for Laravel queues.

4.2k84.2M225](/packages/laravel-horizon)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[spatie/laravel-responsecache

Speed up a Laravel application by caching the entire response

2.8k8.2M51](/packages/spatie-laravel-responsecache)[timacdonald/log-fake

A drop in fake logger for testing with the Laravel framework.

4235.9M56](/packages/timacdonald-log-fake)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
