Sometimes, a lock mechanism is useful in CI workflows, like when you need to prevent simultaneous deployments or block deployments during maintenance.
In this post, I’ll introduce a GitHub Action for implementing a lock mechanism.
https://github.com/suzuki-shunsuke/lock-action
Features
- No dependencies on external services like AWS or GCP
- No reliance on shell or external commands such as git
- Achieves locking using GitHub branches
- Manage branches via GitHub API without git command. You don't have to checkout repositories by actions/checkout
- Records lock and unlock histories
- Supports waiting until a lock is released
How to Use
This action requires two inputs: key and mode.
-
key: an explicit identifier for the lock, which you can adjust by service and environment. -
mode: the action’s operational mode, which can be one of these:-
lock: Acquires a lock -
unlock: Releases a lock -
check: Checks the lock status
-
mode: lock:
steps:
- name: Acquire a lock for a key `foo` before deploying an application
uses: suzuki-shunsuke/lock-action@latest
with:
mode: lock
key: foo
- run: bash deploy.sh foo
mode: unlock:
steps:
- name: Release a lock
uses: suzuki-shunsuke/lock-action@latest
with:
mode: unlock
key: foo
mode: check:
steps:
- name: Check if a key is being locked
id: check
uses: suzuki-shunsuke/lock-action@latest
with:
mode: check
key: foo
- run: bash deploy.sh foo
if: steps.check.outputs.already_locked != 'true'
You can also use post_unlock: "true" to release a lock automatically in a post step.
- uses: suzuki-shunsuke/lock-action@latest
with:
mode: lock
key: foo
post_unlock: "true"
By default, mode: lock will fail if the key is already locked.
Set ignore_already_locked_error: "true" to avoid this.
- uses: suzuki-shunsuke/lock-action@latest
with:
key: foo
mode: lock
ignore_already_locked_error: "true"
To force mode: check to fail if a key is locked, use fail_if_locked: "true".
# This step fails if the key `foo` is being locked.
- uses: suzuki-shunsuke/lock-action@latest
with:
mode: check
key: foo
fail_if_locked: "true"
To wait until a lock is released, use max_wait_seconds and wait_interval_seconds.
- uses: suzuki-shunsuke/lock-action@latest
with:
mode: lock
key: default
# Try to acquire a lock every 10 seconds until acquiring a lock or 60 seconds pass.
max_wait_seconds: "60"
wait_interval_seconds: "10"
These inputs are also available for mode: check.
- uses: suzuki-shunsuke/lock-action@latest
with:
mode: check
key: default
# Check a lock every 5 seconds until the lock is released or 60 seconds pass
max_wait_seconds: "30"
wait_interval_seconds: "5"
How It Works
This action manages locks by creating and updating GitHub branches.
Each lock’s state is tracked in the commit message of a branch named ${{inputs.key_prefix}}${{inputs.key}} (default prefix: lock__, which can be customized with key_prefix).
Commit message format:
unlock by suzuki-shunsuke: test
{
"message": "test",
"state": "unlock",
"actor": "suzuki-shunsuke",
"github_actions_workflow_run_url": "https://github.com/suzuki-shunsuke/test-github-action/actions/runs/11545637203?pr=237",
"pull_request_number": 237
}
From these commit messages, you can see when and who (actor, workflow run, pull request number) acquired or released the lock.
Example links:
Conclusion
In this post, I introduced my GitHub Action for a lock mechanism. For more details, please visit the repository:


Top comments (0)