tourze/symfony-lock-command-bundle
Symfony bundle that adds console commands for managing locks, making it easier to inspect, acquire, and release locks from the CLI. Configuration flows through the Symfony service container, so lock resources can be wired into command workflows without custom glue code.
tourze/symfony-lock-command-bundle is a Symfony bundle (not a Laravel package) that exposes the state of symfony/lock stores through console commands — the operational counterpart to the LockFactory your workers already use. A Laravel developer's interest in it is usually either (a) you run a Symfony service alongside a Laravel app and need a runbook for stuck locks, or (b) you want the CLI surface as a reference implementation for your own Cache::lock() tooling.
Minimal steps:
composer require tourze/symfony-lock-command-bundle
Register the bundle in config/bundles.php (Flex recipe may do this automatically; verify — this package is small enough that a recipe is not guaranteed), and make sure a real lock store is configured via framework.lock / LOCK_DSN so the commands have something to talk to.
Look first at:
vendor/tourze/symfony-lock-command-bundle/src/Command/ — the command names and options are the actual API surface of this package.bin/console list | grep -i lock and bin/console debug:container --tag=console.command | grep -i lock to confirm registration.bin/console debug:container LockFactory / --parameter=lock.* to see which store the commands will hit.First use case: a cron job or queue worker is silently failing because a lock was never released after a crash. You want to list held locks, inspect remaining TTL, and force-release one specific key — without writing a throwaway script.
For Laravel specifically: there is no service provider and no auto-discovery. Either use Laravel's own Cache::lock() for the application path, or, if you genuinely need this CLI, bind a LockFactory in a small service provider and re-register the command classes with $this->commands([...]).
Match the store to the job. The commands are only as useful as the store behind them: Redis/PDO/Doctrine stores are inspectable and support delete/exists; flock and semaphore locks are process-scoped and are released by the OS on process death, so a "list and release stale locks" workflow is largely meaningless there. Decide this before you build a runbook on top of it.
Operational runbook pattern. Wire the list command into your deploy/crash-recovery procedure, scoped by key prefix, and keep a documented TTL convention (e.g. resource-name + ttl = 3 × max expected job duration). The commands become the "who is holding what and for how long" answer during incidents.
Application-side pattern is the Lock component itself:
$lock = $factory->createLock('report:generate:'.$tenantId, 300);
if (!$lock->acquire()) {
return; // another worker owns it — log and bail, don't queue up
}
try {
$this->doLongRunningWork();
} finally {
$lock->release();
}
For jobs that can exceed the TTL, call $lock->refresh() on a heartbeat rather than setting an enormous TTL — a huge TTL turns every crash into a manual intervention, which is exactly what this bundle exists to fix.
Laravel-side integration. If you want equivalent behaviour in-app, prefer Cache::lock('key', 10)->block(5, fn () => ...) and withoutOverlapping() on scheduled commands. Treat this bundle as the out-of-band inspector, not the lock primitive.
CI/deploy hook. Running the listing command post-deploy (read-only) is a cheap smoke test that the store is reachable and permissions are correct — catches misconfigured Redis ACLs before they surface as silent lock-acquire failures in production.
1.0.2...1.1.0 compare link. Review the diff before upgrading, and if you need stability pin ~1.0.2 until the changes are legible. A minor bump on a small package can still contain signature changes to command options.PersistingStoreInterface before trusting the output.getRemainingLifetime() is advisory; Redis TTL granularity and clock skew between hosts mean a lock can expire mid-job. Always have refresh() available for anything long-running.acquire() returns false, it does not throw. Silent no-ops in workers are the usual symptom; log the false branch explicitly.flock files and DB-backed locks. sudo bin/console ... will inspect a different flock namespace than the worker sees.bin/console -vvv <lock-command>, debug:container LockFactory, and debug:config framework lock will tell you more than the package docs will.LockFactory, or a custom PersistingStoreInterface implementation for bespoke backends. The command classes themselves are ordinary Symfony commands and can be extended if you need different output formats (e.g. JSON for alerting).src/ before adopting — it's small enough that this is a ten-minute task and worth more than the README.How can I help you explore Laravel packages today?