Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Coordinator Laravel Package

binary-cats/coordinator

Coordinator is a Laravel package that adds a dedicated coordination layer to your app, giving multi-step workflows a clean home so controllers and services stay thin, focused, and easier to test and maintain.

View on GitHub
Deep Wiki
Context7

Getting Started

Coordinator solves a narrow but very common problem: running a scheduled/queued command on exactly one server in a multi-node deployment, with more control than Laravel's built-in onOneServer().

  1. Install: composer require binary-cats/coordinator
  2. Publish the config: php artisan vendor:publish --tag=coordinator-config (check the package README for the exact tag if this one is renamed).
  3. Open config/coordinator.php first — this is where the default coordinator name, lock store, and strategy live. Read this before touching any command wiring.
  4. Your first use case: wrap an existing scheduled command so only one node runs it.
// app/Console/Kernel.php  (or routes/console.php in Laravel 11+)
$schedule->command('coordinator:run "reports:generate"')->dailyAt('02:00');

The coordinator:run wrapper is the entry point most developers need on day one. Everything else (custom coordinators, strategies) is progressive enhancement.

First thing to verify after 9.1.0: this release only bumps Laravel dependency constraints. Run composer update binary-cats/coordinator and confirm your laravel/framework version is still inside the supported range before deploying — no code changes are required, but the constraint change is exactly the kind of thing that resolves (or introduces) a conflict with other packages pinning Laravel.

Implementation Patterns

Scheduler wrapping (the 80% case). Wrap the command name in coordinator:run inside your scheduler. The coordinator acquires a lock, the winning node executes the inner command, and the rest no-op. Keep the inner command name quoted so arguments pass through cleanly.

Grouping with multiple coordinators. If you have distinct workloads (e.g. reports vs maintenance) that must be independently coordinated, define separate coordinator names in the config rather than sharing one. This prevents a long-running report from blocking unrelated maintenance tasks.

Choosing a strategy. Use the "random"/spread strategy when nodes are equivalent and you just want one winner. Use a priority/first strategy when a specific node (e.g. your primary) should prefer to run the task. Set this per-coordinator in config.

Shared lock store is mandatory. Configure the coordinator to use a cache store backed by Redis or the database — anything shared across nodes. This is the single most important integration decision; see Gotchas.

Testing locally. On a single machine the "only one server" behaviour is invisible. To exercise it, boot two processes pointing at the same Redis cache store (different APP_URL/queues) and confirm only one logs execution. Set your cache store to array in phpunit.xml so tests never touch a real lock.

Composing with withoutOverlapping(). You can still add ->withoutOverlapping() on the outer scheduled entry if a run can exceed its interval; the coordinator lock handles cross-node mutual exclusion, withoutOverlapping handles same-node re-entrancy.

Gotchas and Tips

  • file/array cache = silent failure. If the lock store is per-node, every node thinks it won the lock and the command runs N times. Confirm your cache.default (or the coordinator's explicit store) resolves to Redis/database in production. This is the debugging step when "it runs on every server."
  • Lock TTL vs. long jobs. A lock that expires mid-run lets a second node start the same command. If you have long-running tasks, ensure the lock lifetime in config exceeds worst-case runtime, or use a renewable lock (Redis store) rather than a fixed TTL.
  • Clock skew between nodes. Time-based coordination degrades when servers drift. Keep NTP in sync; if timing matters, prefer lock-acquisition semantics over "run at exactly 02:00" comparisons.
  • Silent no-ops are hard to debug. Non-winning nodes log nothing by default. Add a log line (or check the coordinator's debug output / coordinator:list if available in your version) to confirm which node executed and which skipped.
  • Config cache. After editing config/coordinator.php, run php artisan config:clear locally and remember config:cache in production bakes the values in — a stale cached config is a frequent "why is my strategy still random?" cause.
  • 9.1.0 upgrade note. Pure dependency bump — treat it as a composer update + verify deploy. There are no deprecations or behavioural changes to migrate. Pin the exact version in composer.json if your CI is sensitive to transitive Laravel constraint changes.
  • Extension point. If you outgrow coordinator:run, the config-driven coordinator classes are the place to subclass/extend for custom election logic — but validate the lock store wiring first, since that's where most extension attempts fail.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json