Skip to content

Preventing simultaneous deployment jobs

development

Two deployments changing the same environment can overwrite files, race migrations or restart each other’s processes. Give each environment a clear deployment concurrency boundary.

What you need before you begin

Identify every path that can deploy, including CI, manual scripts and panel tools. Decide what should happen when a second deployment arrives while one is running.

01 Prevent simultaneous deployment jobs

  1. Configure the CI platform’s concurrency group or deployment lock for the target environment. Use different groups for genuinely independent environments.

  2. Choose whether later jobs queue or replace a pending job. Avoid cancelling an active migration or release switch without a recovery-aware design.

  3. Include manual deployment paths in the same coordination process. A CI-only lock cannot stop an administrator running a separate script.

  4. Record the active release and current deployment phase. Make a retry detect whether preparation, migration or activation already completed.

  5. Test two harmless staging deployments submitted close together and confirm the resulting order and final release.

02 Example: serialize a GitHub Actions deployment

For a reviewed GitHub Actions workflow targeting one production environment, the following workflow-level fragment serializes runs within its repository. It is a concurrency fragment, not a complete deployment workflow.

Code or configuration example
concurrency:
  group: production-deploy
  cancel-in-progress: false
  queue: max

Current GitHub Actions supports up to 100 pending runs with queue: max. Without it, the default allows one pending run and a newer pending run replaces the earlier one. This configuration does not cancel an active deployment; do not combine the expanded queue with cancel-in-progress: true.

Use the same group for workflows that mutate this same environment, and a separate group for an independent staging environment. A manual deployment or another repository still needs coordination outside this repository-level control. Verify the active release and queued order in staging before using the workflow for production.

Confirm the expected result

Verify only the intended job mutates the environment at one time and that a cancelled or failed job releases its lock correctly. Check the final release record matches the active code.

Troubleshoot unexpected results

If a job appears stuck, investigate its actual process and database activity before deleting a lock. Removing a valid lock can allow a second mutation to begin.

A common question

Should every new commit immediately cancel the running deployment?

That may be suitable for a disposable preview build, but a production mutation needs phase-aware handling. Queueing can be safer when the active job is changing persistent state.

Sources and further reading

Was this answer helpful?

Need a little more help?

Our support team can help you find the next step.

Contact support