Developers

Automate locks in CI

Lock a shared environment at the start of a CI job and release it at the end, even when the job fails.

If a pipeline deploys to a shared environment, have it lock that environment first. Your team sees the deploy in Lockit like any other lock, and two pipelines can't deploy over each other.

What you need

  • An API key with write scope, saved as a secret in your CI. The example below uses a GitHub Actions secret called LOCKIT_API_KEY.
  • The email of a member of your Slack workspace for the lock to be held under.

Check the response body, not just the status

When a lock is refused, for example because someone else holds the resource, the API still returns HTTP 200. The body starts with Error:. A script that only checks the status code will carry on as if it had the lock.

GitHub Actions example

name: Deploy to staging
on: workflow_dispatch

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      LOCKIT_API: https://api.lockitbot.com/api/locky
      RESOURCE: staging-db
    steps:
      - uses: actions/checkout@v4

      - name: Lock staging-db
        id: lock
        run: |
          body=$(curl -sS --fail-with-body -X POST \
            -H "X-API-KEY: ${{ secrets.LOCKIT_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{"userEmail":"you@company.com","duration":60}' \
            "$LOCKIT_API/resources/$RESOURCE/lock")
          echo "$body"
          case "$body" in Error:*) exit 1 ;; esac

      - name: Deploy
        run: ./deploy.sh staging

      - name: Release staging-db
        if: always() && steps.lock.outcome == 'success'
        run: |
          curl -sS --fail-with-body -X POST \
            -H "X-API-KEY: ${{ secrets.LOCKIT_API_KEY }}" \
            "$LOCKIT_API/resources/$RESOURCE/release"

How it works:

  1. Lock asks for a 60-minute lock (duration is in minutes) and fails the job if the body starts with Error:.
  2. Deploy runs only if the lock succeeded.
  3. Release runs even when the deploy fails or is cancelled (always()), so a broken build doesn't leave the environment locked. It's skipped when the lock step failed, so the job never releases a lock someone else holds.

Set duration a little longer than the job normally takes. If the runner dies before the release step, the lock still ends on its own.