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)