DEV Community

Cover image for Triggering Github workflows from other repositories, now with locking
Dave Cozens
Dave Cozens

Posted on

Triggering Github workflows from other repositories, now with locking

OK, so we live in a world of automation and GitHub Actions, because nobody wants to deploy things themselves, right?

Sometimes you have multiple repositories, because code separation is fun and we need to be able trigger downstream builds in a different repository using github actions.

Easy, you say? Comes out of the box with GitHub Actions...

Repository A:

...
    - name: Trigger my downstream workflow
        run: |
          curl -XPOST -u "${{ secrets.GIT_CREDENTIALS }}" -H "Accept:application/vnd.github" -H "Content-Type:application/json" https://api.github.com/repos/path/to/workflow.yml/dispatches --data '{"ref": "main" }'
...
Enter fullscreen mode Exit fullscreen mode

Repository X:

name: Deploy Repo X
on:
  workflow_dispatch:
    inputs:
      source:
        description: 'Source of event'
        required: false
        default: 'No source specified'
...
Enter fullscreen mode Exit fullscreen mode

...and off we go. Easy peasy.

But there's a downside here. Let's say we've got multiple repositories that all need to do the same thing. If any of Repos A, B, C & D change they need to trigger a build of Repo X.

Great. No problemo.

However, if all 4 repos change at once, we get 4 builds. That'll tie up the build system for an hour. Horrible log jam. Angry developers. The works. And GitHub don't provide any kind of build throttling (are you listening GitHub? ARE YOU???)

What we need is a way to prevent multiple repos from submitting a new pending job if one of its siblings had recently done the same thing.

Sounds like a job for Redis (he said with the benefit of hindsight).

SET buildlock 1 NX EX 180
Enter fullscreen mode Exit fullscreen mode

enables us to set a buildlock key in Redis with an expiry of 3 minutes. The important thing here is that if the key is successfully set, Redis returns "OK", otherwise "(nil)".

So, without further ado, here's a way of only firing workflows on an upstream repo if something else hasn't recently done so:

name: Update components
on:
  push:
    branches:
      - main
jobs:
  TriggerPlatformDeploy:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    env:
      ENVIRONMENT: "dev"
    steps:
      - name: Install redis CLI
        run: |
          sudo apt-get install redis-tools -y
      - name: Check for recent push lock
        run: |
          didSet=$(redis-cli -a ${{ secrets.REDIS_TOKEN }} -h ${{ secrets.REDIS_URL }} -p$ {{ secrets.REDIS_PORT }} --no-auth-warning SET buildlock 1 NX EX 180)
          echo "didSet=$(echo $didSet)" >> $GITHUB_ENV
      - name: Trigger workflow if not locked
        if: env.didSet == 'OK'
        run: |
          curl -XPOST -u "${{ secrets.GIT_CREDENTIALS }}" -H "Accept:application/vnd.github" -H "Content-Type:application/json" https://api.github.com/repos/path/to/workflow.yml/dispatches --data '{"ref": "main" }'
      - name: Workflow is locked
        if: env.didSet != 'OK'
        run: |
          echo Suppressing build trigger because another repo has triggered within 3 minutes
Enter fullscreen mode Exit fullscreen mode

Top comments (0)