Skip to main content
When multiple users share a Lager Box, locks prevent conflicting operations. Lager provides two locking mechanisms: automatic command locks that protect running commands, and user locks for explicit reservation.

How It Works

Automatic Command Lock

Every command that targets a box automatically acquires a command lock before it runs. This prevents two users from issuing conflicting commands to the same box at the same time.
  • All callers blocked: Any command targeting the same box is blocked until the first command finishes, even from the same user
  • Auto-expires: After 30 minutes of inactivity, stale command locks are automatically cleaned up
  • Released on completion: The lock is released when the command finishes or when you press Ctrl+C
If a command is already in progress, you’ll see:
Error: Box 'lab-box' is busy — 'python' in progress by alice. Use --force-command to override.

User Lock

A user lock is an explicit, persistent lock you place on a box. Unlike command locks, user locks do not expire — you must manually unlock the box when you’re done. Use cases:
  • Reserving a box for an extended debugging session
  • Preventing others from using a box during maintenance
  • Claiming a box when you’re not actively running a command

Commands

lager boxes lock

Lock a box to prevent others from using it.
lager boxes lock --box NAME
Options:
  • --box (required) - Name of the box to lock
Example:
lager boxes lock --box lab-box

# Output:
Box 'lab-box' locked by alice at 2026-03-20T14:30:00Z
If the box is already locked by another user:
Error: Box 'lab-box' is already locked by bob (since 2026-03-20T13:00:00Z)

lager boxes unlock

Unlock a box to allow others to use it.
lager boxes unlock --box NAME [--force]
Options:
  • --box (required) - Name of the box to unlock
  • --force - Force unlock even if the box was locked by another user
Examples:
# Unlock your own lock
lager boxes unlock --box lab-box

# Force unlock a box locked by someone else
lager boxes unlock --box lab-box --force

Bypassing Locks

--force-command

Use the --force-command flag to bypass both command locks and user locks:
lager python script.py --box lab-box --force-command
The --force-command flag is available on all subcommands that target a box. This is useful when you know it’s safe to proceed despite an existing lock (e.g., a stale lock from a disconnected session).

Management operations

The following operations skip lock checks entirely because they manage running processes rather than starting new ones:
  • lager python --kill ID
  • lager python --kill-all
  • lager python --reattach ID

lager boxes

When boxes are locked or busy, lager boxes shows additional columns:
 name        ip               version   status    locked by   busy
==========================================================================
 lab-box-1   100.x.x.1        0.12.0    current   alice
 lab-box-2   100.x.x.2        0.12.0    current               bob (python)
 lab-box-3   100.x.x.3        0.12.0    current
  • Locked By — shows the user who placed an explicit lock (magenta)
  • Busy — shows the user and command currently in progress (yellow)
These columns only appear when at least one box is locked or busy.

Special Cases

--detach keeps the command lock

When you run a command with --detach, the command lock is held until the detached process finishes on the box. This prevents other users from accidentally interfering with your running script.
# Lock is acquired and held until the script finishes on the box
lager python long_test.py --box lab-box --detach

# Other users are blocked until the detached script completes
lager hello --box lab-box
# Error: Box 'lab-box' is busy — 'python' in progress by alice. Use --force-command to override.

lager update --all skips locked boxes

When updating all boxes at once, locked or busy boxes are skipped rather than blocking the update:
Updating all boxes...
  lab-box-1: updated to 0.12.0
  lab-box-2: SKIPPED (locked or busy)
  lab-box-3: updated to 0.12.0

Stale lock auto-expiry

Command locks older than 30 minutes are automatically cleaned up. This handles cases where a client disconnects without releasing its lock (e.g., network failure, laptop sleep). User locks do not expire.

Examples

Multi-user workflow

# Alice starts a test
alice$ lager python test_suite.py --box lab-box

# Bob tries to use the same box — blocked
bob$ lager python quick_check.py --box lab-box
# Error: Box 'lab-box' is busy — 'python' in progress by alice. Use --force-command to override.

# Alice's test finishes — lock released automatically
# Bob can now use the box
bob$ lager python quick_check.py --box lab-box

Running a long detached script

# Detached scripts hold the command lock until they finish
lager python overnight_test.py --box lab-box --detach

# To check on it later
lager python --reattach <PROCESS_ID> --box lab-box

# To stop it early
lager python --kill <PROCESS_ID> --box lab-box