Skip to main content

Implementing Concurrency Control

1. Setting Workflow Concurrency

Property Values Description
concurrency string or object Controls how workflows are handled when concurrent runs exist.

Example: Basic Concurrency Configuration

name: Example Workflow
on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: "build-${{ github.ref }}"
      cancel-in-progress: true
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
Note: The concurrency key is defined at the job level, not workflow level.
Field Type Description
group string Defines the concurrency group. All workflows in the same group will be queued or canceled based on cancel-in-progress.
cancel-in-progress boolean If true, cancels any in-progress workflow in the same group. Defaults to false.

2. Defining Concurrency Group

Property Description Values Notes
concurrency.group Defines the concurrency group for a workflow {% raw %}${{ github.workflow }}{% endraw %} or custom string Used to control concurrent runs of a workflow
concurrency.cancel-in-progress Cancel in-progress runs when a new run is triggered true or false Defaults to false

Example: Defining Concurrency Group

name: Example Workflow
on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: ${{ github.workflow }}
      cancel-in-progress: true
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

3. Canceling In-Progress Runs

Option Values Notes
concurrency group: ${{ github.workflow }} Cancel in-progress runs in the same workflow
concurrency.cancel-in-progress true Cancel previous runs when a new one starts

Example: Canceling in-progress runs

name: CI
on:
  push:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: ${{ github.workflow }}
      cancel-in-progress: true
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
Note: The concurrency key is used to define a group of workflows that should be mutually exclusive. When cancel-in-progress is set to true, any in-progress run in the same group will be canceled when a new run starts.

4. Using Branch-Based Concurrency

Branch Type Description Use Case Trigger
main Primary branch for production code Stable releases, deployment to production Manual or automated on push
develop Integration branch for features Collaborative development, testing Push or merge to develop
feature/<name> Feature-specific branches Isolated development, code review Push to feature branch
release/<version> Release preparation branches Final testing, version tagging Manual creation or merge from develop
hotfix/<name> Emergency fixes to production Quick bug fixes, patch releases Push to hotfix branch

Example: Branch Protection Rules

name: Branch Protection
on:
  push:
    branches:
      - main
      - develop
jobs:
  enforce_branch_protection:
    runs-on: ubuntu-latest
    steps:
      - name: Check branch protection rules
        run: |
          echo "Ensuring only allowed branches can merge to main"
          # Implementation logic here
Note: Using branch strategies helps manage concurrent development and ensures code quality through automated checks.

Summary of Branch-Based Concurrency

  • main is for stable, production-ready code.
  • develop is for ongoing feature development and integration.
  • feature/<name> isolates feature development.
  • release/<version> prepares for release.
  • hotfix/<name> handles urgent production fixes.

5. Using PR-Based Concurrency

GitHub Actions supports concurrent workflow execution, but can be configured to limit concurrency based on pull requests (PRs) to prevent conflicts or resource contention. This is particularly useful in environments where workflows might interfere with each other.

Option Values Description
concurrency.group ${{ github.workflow }}-${{ github.ref }} Defines the concurrency group. By default, workflows in the same group are cancelled if a new workflow starts.
concurrency.cancel-in-progress true When set to true, cancels any in-progress workflow runs in the same concurrency group.

Example: PR-Based Concurrency Configuration

name: PR-Based Concurrency
on:
  pull_request:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: pr-${{ github.event.number }}
      cancel-in-progress: true
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Run tests
        run: npm test
Note: The concurrency.group can be customized to include PR numbers or branch names to ensure that workflows for different PRs don't interfere with each other.

6. Setting Job-Level Concurrency

Property Values Description
concurrency string or object Controls the concurrency behavior for jobs in a workflow.

Example: Basic concurrency configuration

name: Example Workflow
on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: "build-${{ github.ref }}"
      cancel-in-progress: true
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
Note: The concurrency property can be defined at the job level or workflow level. When set at the job level, it overrides any workflow-level concurrency settings for that specific job.
Field Type Description
group string Defines the concurrency group name. Jobs in the same group are considered part of the same concurrency set and will cancel each other if a new job starts.
cancel-in-progress boolean If true, cancels any in-progress job in the same concurrency group when a new job is started. Defaults to false.

Example: Using variables in concurrency group

jobs:
  test:
    runs-on: ubuntu-latest
    concurrency:
      group: "test-${{ github.ref }}-${{ github.run_id }}"
      cancel-in-progress: true

7. Using Dynamic Concurrency Groups

Dynamic concurrency groups in GitHub Actions allow you to control the number of concurrent workflow runs based on runtime conditions or external factors. This is particularly useful for managing resource usage and ensuring that workflows don't overwhelm shared resources like databases or API endpoints.

Property Description Values Notes
concurrency Defines the concurrency group for a workflow string Can include variables and expressions. If not set, workflows run concurrently without restriction.
concurrency.cancel-in-progress Controls whether to cancel in-progress runs when a new run is started true or false Defaults to false. When set to true, new runs will cancel any in-progress runs in the same group.

Example: Setting up a Dynamic Concurrency Group

name: Dynamic Concurrency Example
on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: "build-${{ github.ref }}"
      cancel-in-progress: true
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Run build
        run: echo "Building..."
Note: The concurrency.group can use context variables like github.ref, github.head_ref, or github.sha to dynamically create unique groups per branch or commit.
Warning: Setting cancel-in-progress to true can lead to race conditions or incomplete builds if not carefully managed. Ensure that your workflows are resilient to cancellation.

8. Preventing Parallel Deployments

Parallel deployments can lead to race conditions, inconsistent states, or resource conflicts. GitHub Actions provides several mechanisms to prevent concurrent deployments and ensure controlled execution.

Mechanism Description Usage
concurrency Controls the concurrency of workflow runs. If a workflow is already running, subsequent runs are queued or canceled.
concurrency:
  group: "deployment"
  cancel-in-progress: true

Example: Using Concurrency to Prevent Parallel Deployments

name: Deploy
on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    concurrency:
      group: "deployment"
      cancel-in-progress: true
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Deploy to production
        run: echo "Deploying..."
Note: The concurrency key ensures that only one deployment job can run at a time within the same group. Setting cancel-in-progress to true cancels any in-progress jobs in the same group.

Best Practices for Concurrency Control

  • Use a unique group name per deployment environment (e.g., deployment-staging, deployment-production) to isolate workflows.
  • Enable cancel-in-progress to prevent outdated deployments from running.
  • Combine concurrency with needs or if conditions to enforce deployment order or dependencies.

9. Queuing Workflow Runs

GitHub Actions allows queuing of workflow runs when the maximum concurrency limit is reached. This ensures that workflows are not skipped and instead wait in a queue until resources become available.

Property Description Default Value
concurrency Controls the concurrency of workflow runs. When set, only one run from the same workflow can be active at a time. None
concurrency.group Defines the group name for concurrency. Runs in the same group are queued if a previous run is active. None
concurrency.cancel-in-progress When set to true, cancels any in-progress runs from the same group. false

Example: Configuring Concurrency

name: Example Workflow
on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: ${{ github.workflow }}-${{ github.ref }}
      cancel-in-progress: true
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
Note: The concurrency setting is useful for preventing multiple workflow runs from running simultaneously in environments with limited resources.
Warning: Setting cancel-in-progress to true will cancel any in-progress workflow runs from the same group, which may lead to incomplete builds.

10. Using Actor in Concurrency

Property Description Example
actor.name Name of the actor instance "user-service"
actor.state Current state of the actor (e.g., active, idle) "active"
actor.maxConcurrent Maximum number of concurrent operations allowed 5

Example: Actor Configuration

name: Actor Concurrency
on:
  workflow_dispatch:
jobs:
  run-actor:
    runs-on: ubuntu-latest
    steps:
      - name: Initialize Actor
        uses: actions/actor-init@v1
        with:
          actor-name: "user-service"
          max-concurrent: 5
Note: Actor concurrency in GitHub Actions is managed through job-level isolation and resource limits. Each actor runs in its own isolated environment.
Warning: Exceeding max-concurrent limits may cause job failures or throttling.

Actor Concurrency Best Practices

  • Use actors to isolate stateful operations.
  • Set max-concurrent based on system resource availability.
  • Monitor job execution logs for actor state transitions.

11. Handling Concurrency with Matrix

Property Description Values Notes
strategy.matrix Defines the matrix of build configurations { os: [ubuntu-latest, windows-latest], node-version: [14, 16, 18] } Each combination creates a separate job
strategy.matrix.include Adds additional job configurations to the matrix { os: macos-latest, node-version: 18, arch: arm64 } Useful for including special cases or experimental setups
strategy.matrix.exclude Removes specific job configurations from the matrix { os: windows-latest, node-version: 14 } Allows filtering out incompatible or unwanted combinations

Example: Matrix Strategy Configuration

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    node-version: [14, 16, 18]
    include:
      - os: macos-latest
        node-version: 18
        arch: arm64
    exclude:
      - os: windows-latest
        node-version: 14
Note: Matrix jobs run in parallel, so ensure your infrastructure can handle concurrent executions.
Warning: Excessive matrix combinations can lead to high resource consumption and job timeouts.

12. Monitoring Concurrent Runs

Aspect Description Notes
concurrency 1 Controls how many workflow runs can execute concurrently in a repository
concurrency.group ${{ github.workflow }}-${{ github.ref }} Defines the group of workflows that are mutually exclusive
concurrency.cancel-in-progress false When true, cancels in-progress runs when a new run is triggered

Example: Configuring Concurrency Control

name: "Concurrent Workflow Control"
on:
  push:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: "build-${{ github.ref }}"
      cancel-in-progress: true
    steps:
      - name: "Checkout Code"
        uses: actions/checkout@v4
Note: The concurrency.group value must be unique per workflow to prevent unintended cancellation of runs.

Key Points

  • Use concurrency to limit simultaneous workflow executions.
  • Set cancel-in-progress to true to cancel older runs when new ones start.
  • Define a unique group to control which workflows are considered concurrent.

Was this article helpful?