PHPackages                             nemanjajojic/tick - 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. [Logging &amp; Monitoring](/categories/logging)
4. /
5. nemanjajojic/tick

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

nemanjajojic/tick
=================

Tick — a PHP task scheduler. One tick per cron minute. No daemon, no framework, no surprises.

v0.4.0(3w ago)01MITPHPPHP ^8.2

Since May 14Pushed 3w agoCompare

[ Source](https://github.com/nemanjajojic/tick)[ Packagist](https://packagist.org/packages/nemanjajojic/tick)[ RSS](/packages/nemanjajojic-tick/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (4)Dependencies (11)Versions (5)Used By (0)

Tick
====

[](#tick)

[![PHP 8.2+](https://camo.githubusercontent.com/187240af044d09d5b14a1d9d9ebdf3f7a993e4c7bc09bdb46b4ba661a891bf5b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d626c7565)](https://camo.githubusercontent.com/187240af044d09d5b14a1d9d9ebdf3f7a993e4c7bc09bdb46b4ba661a891bf5b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d626c7565)[![License: MIT](https://camo.githubusercontent.com/5caa455d8debc46fb23abbadb45a733a937f3910a73fc875c2f7820468e1bb54/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d677265656e)](https://camo.githubusercontent.com/5caa455d8debc46fb23abbadb45a733a937f3910a73fc875c2f7820468e1bb54/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d677265656e)[![PHPStan: max](https://camo.githubusercontent.com/71936661c994bdd70ec588a6771c605f8584906d8054c5d607a3bcc6bd943f3c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6d61782d627269676874677265656e)](https://camo.githubusercontent.com/71936661c994bdd70ec588a6771c605f8584906d8054c5d607a3bcc6bd943f3c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6d61782d627269676874677265656e)[![PHPUnit: 432 tests](https://camo.githubusercontent.com/5d10d31bba4774ee1bdf747ee855b41fb92af6eadd6a4c10d013b143d7b8c0d9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f504850556e69742d34333225323074657374732d627269676874677265656e)](https://camo.githubusercontent.com/5d10d31bba4774ee1bdf747ee855b41fb92af6eadd6a4c10d013b143d7b8c0d9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f504850556e69742d34333225323074657374732d627269676874677265656e)[![Code Coverage: 100%](https://camo.githubusercontent.com/8000986f3f8ae4c5d2eb1fc9fa68a1f003a9f3f631ad54404a52116a9066d665/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436f6465253230436f7665726167652d3130302532352d627269676874677265656e)](https://camo.githubusercontent.com/8000986f3f8ae4c5d2eb1fc9fa68a1f003a9f3f631ad54404a52116a9066d665/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436f6465253230436f7665726167652d3130302532352d627269676874677265656e)[![Infection MSI: 90%](https://camo.githubusercontent.com/c10ce396c00dac910f2a227362d194c854a55db44a3e8e666aa6ddd77c87d2d8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f496e66656374696f6e2532304d53492d39302532352d627269676874677265656e)](https://camo.githubusercontent.com/c10ce396c00dac910f2a227362d194c854a55db44a3e8e666aa6ddd77c87d2d8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f496e66656374696f6e2532304d53492d39302532352d627269676874677265656e)

**Tick is a PHP task scheduler. One tick per cron minute. No daemon, no framework, no surprises.**

A modern, framework-agnostic PHP 8.2+ task scheduler library with strict typing, PSR-3 / PSR-20 interfaces, optional Symfony Console command classes, and first-class support for locking, retry policies, and runtime constraints. Designed for Slim, Mezzio, and DevOps-oriented teams who want explicit control over their scheduled tasks without framework coupling or hidden globals.

Architecture
------------

[](#architecture)

For an architectural overview of Tick's components and their runtime interactions, see [docs/architecture.md](docs/architecture.md).

### Design Decisions

[](#design-decisions)

- **Pure library, no daemon, no framework coupling**: The scheduler is invoked externally (typically via cron). No long-running process, no framework-specific integrations.
- **PSR-3 / PSR-20 interfaces only**: Logging and time are abstracted via standard interfaces, enabling easy testing and integration.
- **Pluggable behavior via small, single-purpose interfaces**: Tick ships `LockInterface` (`FileLock`), `TaskInterface` (`CallableTask`, `RawTask`), `RetryPolicyInterface` (5 built-in policies), and `TaskDispatcherInterface` (default, dry-run, timing decorator). Every concern that users may need to swap or decorate is an interface — bring your own Redis lock, queue-pushing task, or custom retry policy without forking the library.
- **Fluent builder with once-only guards**: Calling `cron()` / sugar methods, `withoutOverlapping()`, `retry()`, or constraint methods more than once throws `InvalidScheduleException`. This prevents accidental misconfiguration.
- **Name is supplied at registration, not inside the task**: Tasks are reusable; the name is a property of the registration, not of the task object.

Boundary: What the Library Ships vs. What You Provide
-----------------------------------------------------

[](#boundary-what-the-library-ships-vs-what-you-provide)

**The library ships:**

- `Scheduler` class with three explicit registration methods: `call()`, `invoke()`, `raw()`
- Two built-in task adapters (`CallableTask`, `RawTask`) plus the open `TaskInterface` contract
- Cron expression parsing (via `dragonmantank/cron-expression`)
- File-based locking (`FileLock`) with `flock()` semantics
- Retry policies (`NoRetryPolicy`, `ConstantBackoffRetryPolicy`, `LinearBackoffRetryPolicy`, `JitteredExponentialBackoffRetryPolicy`, `DecorrelatedJitterRetryPolicy`)
- Runtime constraints (`when()`, `skip()`)
- Dry-run dispatcher and timing decorator
- Four optional Symfony Console command classes (`RunCommand`, `ListTasksCommand`, `RunTaskCommand`, `UpcomingCommand`)

**You provide:**

- Composition root that builds the `Scheduler` and registers tasks
- Console wiring — if you want the CLI commands, you instantiate `Symfony\Component\Console\Application` and add the four command classes yourself (no binary or autodiscovery is shipped)
- Container setup (PHP-DI, Pimple, or manual wiring) — only if you use containers
- Task implementations (your business logic, as closures or `TaskInterface` objects)
- Crontab entry to invoke the scheduler every minute
- Custom `LockInterface` if you need Redis/database locks

Installation
------------

[](#installation)

### Core (library only)

[](#core-library-only)

```
composer require nemanjajojic/tick
```

This gives you the `Scheduler`, all task adapters, dispatchers, locks, and retry policies. **Zero framework dependencies.** Use this if you call `$scheduler->run()` directly from your own application (Slim middleware, a Laravel command, a cron-invoked PHP script, etc.).

### With the optional Console commands

[](#with-the-optional-console-commands)

```
composer require nemanjajojic/tick symfony/console
```

This makes the four command classes (`RunCommand`, `ListTasksCommand`, `RunTaskCommand`, `UpcomingCommand`) usable. **Tick does not ship a binary or an `Application` factory** — you instantiate `Symfony\Component\Console\Application` and add the commands yourself. See [Pattern 2](#pattern-2-standalone-symfony-cli-with-php-di) below for a complete `bin/` script. `symfony/console` is a **suggested** dependency, not a hard one. The CLI is convenience, not the product; you can use the entire scheduler without it.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Composer 2

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

[](#quick-start)

The `Scheduler` provides three explicit registration methods. Each requires a name as the first argument.

```
