Download the PHP package nemanjajojic/tick without Composer

On this page you can find all versions of the php package nemanjajojic/tick. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package tick

Tick

PHP 8.2+ License: MIT PHPStan: max PHPUnit: 432 tests Code Coverage: 100% Infection MSI: 90%

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

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

Design Decisions

Boundary: What the Library Ships vs. What You Provide

The library ships:

You provide:

Installation

Core (library only)

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

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 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

Quick Start

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

Usage Patterns

There are three integration patterns, from least to most CLI tooling. All three build a Scheduler in user code; Tick does not impose a bootstrap-file convention.

  1. Pure library — call $scheduler->run() from your own PHP entry point. No symfony/console, no command classes.
  2. Standalone Symfony Console application — install symfony/console, add the three Tick command classes to your own Application, invoke via cron.
  3. Framework command bus — register the three Tick command classes as services in your existing Symfony / Laravel / Mezzio app and let your framework's console front-controller run them.

Pattern 1: Pure library (no CLI, no Symfony)

The smallest possible deployment: a single PHP script that builds a Scheduler, registers tasks, and calls run(). Invoked once per minute from cron. No bootstrap indirection, no symfony/console, no framework.

Create cron/scheduler.php:

GenerateReports is any class implementing NemanjaJojic\Tick\Task\TaskInterface:

Crontab entry:

That is the entire integration. No symfony/console, no command classes, no CLI binary. This pattern suits:

Pattern 2: Standalone Symfony CLI with PHP-DI

When you want a proper CLI with tick:list, tick:run-task, and tick:upcoming for ops and debugging, install symfony/console, build your own Application, and add Tick's four command classes. There is no vendor/bin/tick and no --bootstrap option — you own the entry point and the wiring.

Create bin/my-scheduler:

Make the script executable:

Crontab entry:

This pattern suits:

Pattern 3: Framework command bus (Slim + PHP-DI)

Slim is an HTTP micro-framework and intentionally ships no console layer. The idiomatic way to "register Tick as services" in a Slim app is to reuse the same PHP-DI container Slim already uses for HTTP, and let the container build both the Scheduler and the three command classes. A thin bin/console entry point then turns container services into a Symfony Application. There is no Tick-specific bootstrap and no per-command construction in user code.

Define the services once in your existing PHP-DI definitions file (config/container.php or wherever Slim loads them):

Both your Slim public/index.php and your bin/console build the same container. The console entry point pulls the three commands out of the container and registers them on a Symfony Application:

Invoke through your project's single console:

This pattern suits teams who already have a Slim HTTP app, want one DI container for both web and CLI, and don't want a separate scheduler entry point. Substitute Mezzio (same PHP-DI / Aura.Di approach) or Laminas (Laminas\Cli) with equivalent service definitions.

CLI Reference

The five Console command classes Tick ships:

Class Name Purpose
RunCommand tick:run Run all due tasks (single tick). Cron-friendly.
ListTasksCommand tick:list List registered task names, one per line.
RunTaskCommand tick:run-task Force-run a single task by name. Honors lock and constraints.
UpcomingCommand tick:upcoming Show upcoming task occurrences without executing anything.
DetailCommand tick:detail Show full configuration for a single task plus the next N runs.

For full usage, options, sample output, exit codes, and flock/systemd deployment recipes, see docs/cli.md.

Configuration Reference

The TaskBuilder returned by registration methods provides these configuration methods. Each method enforces a once-only contract: calling it twice throws InvalidScheduleException.

Schedule Methods

Method Cron Expression Description
cron(string $expression) Custom Any valid cron expression
everyNMinutes(int $minute) */{minute} * * * * Every N minutes (1-59)
hourly() 0 * * * * At minute 0 of every hour
hourlyAt(int $minute) {minute} * * * * At specified minute of every hour
daily() 0 0 * * * At midnight
dailyAt(string $time) {minute} {hour} * * * At specified time (HH:MM format)
weekly() 0 0 * * 0 At midnight on Sunday
weeklyOn(int $day, string $time) {minute} {hour} * * {day} At specified time on specified day (0=Sunday)
monthly() 0 0 1 * * At midnight on the 1st
monthlyOn(int $day, string $time) {minute} {hour} {day} * * At specified time on specified day of month
yearly() 0 0 1 1 * At midnight on January 1st

Behavior Methods

Method Description
withoutOverlapping(int $ttlSeconds = 3600) Prevent concurrent execution via lock
retry(RetryPolicyInterface $policy) Configure retry behavior on failure
when(Closure $predicate) Run only if predicate returns true
skip(Closure $predicate) Skip if predicate returns true
describe(string $description) Attach a human-readable description (max 500 chars, surfaced by tick:detail)

Task Descriptions

describe() attaches free-form documentation to a task. The description is stored on the RegisteredTask value object and surfaced by the tick:detail console command (both table and json formats). It does not affect scheduling or execution.

Validation rules (enforced at build time, throw InvalidScheduleException):

Overlap Protection (Locking)

Use withoutOverlapping() to prevent concurrent execution of the same task:

The lock key is the task name. The lock is held for the entire dispatch duration (including retry attempts and backoff sleeps). If the scheduler ticks again while a previous dispatch is still running, the subsequent tick observes LOCK_BUSY and is skipped.

The FileLock implementation uses kernel-level flock() with LOCK_EX | LOCK_NB for non-blocking acquisition. Locks are automatically released when the process exits.

Disabling Overlap Protection

For dev/local environments where overlap protection is undesirable, or for tests that exercise tasks declared with withoutOverlapping() without needing a writable filesystem, pass an inline no-op LockInterface implementation:

Do NOT use a no-op lock in production multi-tick deployments — overlap protection is silently disabled.

Custom Lock Implementations

Implement LockInterface for Redis, database, or other backends:

Retry Policies

NoRetryPolicy (Default)

Executes the task once. If it fails, the failure is recorded without retrying. This is the default if retry() is not called.

ConstantBackoffRetryPolicy

Retries with a constant delay between attempts:

LinearBackoffRetryPolicy

Retries with linearly increasing delays, optionally capped. See AWS Architecture Blog: Exponential Backoff And Jitter for background on retry-delay strategies:

JitteredExponentialBackoffRetryPolicy

AWS "full jitter" strategy. Spreads retries across the time window to avoid thundering-herd contention against a recovering downstream:

DecorrelatedJitterRetryPolicy

AWS "decorrelated jitter" strategy. Produces good spread while avoiding the long-tail variance of full jitter. Recommended default for retry storms against shared infrastructure:

Custom Retry Policy

Implement RetryPolicyInterface:

Constraints (when / skip)

Use when() and skip() to gate a due task behind a runtime predicate. The predicate is evaluated on every tick where the task's schedule matches.

when() — Feature Flags and Environment Gating

skip() — Maintenance Windows

Predicate Contract

Observability

Tick has no built-in logger. To get structured PSR-3 logs of every dispatch outcome, wrap your dispatcher with LoggingTaskDispatcherDecorator:

The decorator emits one log entry per dispatch and catches any Throwable raised by the inner dispatcher (logged at critical), returning a synthetic DispatchResult::failed() so the loop continues.

Log levels:

Outcome Level Message
COMPLETED info Tick: task completed.
FAILED error Tick: task failed.
LOCK_BUSY info Tick: task skipped (lock not acquired).
DRY_RUN info Tick: would run.
SKIPPED_BY_CONSTRAINT (predicate returned false) info Tick: task skipped (constraint).
SKIPPED_BY_CONSTRAINT (predicate threw) error Tick: constraint predicate failed.
inner dispatcher threw critical Tick: dispatcher threw; task skipped.

Without the decorator, the scheduler is silent. Dispatcher exceptions propagate.

Dry Run

The scheduler delegates execution to a TaskDispatcherInterface. Two implementations ship with the library:

Pick the dispatcher at the composition root:

In dry-run mode, constraint predicates are still evaluated (their side effects will fire). This is deliberate: dry-run reports what the real run would actually do given current runtime state.

Composing Dispatchers

The TaskDispatcherInterface allows decorator composition. The library ships TimingTaskDispatcherDecorator for execution timing:

The timing decorator adds timing.durationMs to the DispatchResult::$logContext, which the LoggingTaskDispatcherDecorator includes in log entries when both decorators are chained.

Timezones

The Scheduler constructor takes a required DateTimeZone. Cron expressions are evaluated against wall-clock time in this timezone:

Multiple Timezones

Instantiate multiple Scheduler instances for different timezone cohorts:

Recommendation

Run servers in UTC, keep ClockInterface in UTC, and let the Scheduler timezone be the only zoned component. This eliminates ambiguity in logs and audit trails.

Development with Docker

The compose.yml provides a php service (PHP 8.2-cli-alpine).

Contributing

See CONTRIBUTING.md for the contribution workflow, quality gates, and coding standards.

License

MIT License. See LICENSE for details.


All versions of tick with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
dragonmantank/cron-expression Version ^3.3
psr/clock Version ^1.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package nemanjajojic/tick contains the following files

Loading the files please wait ...