GitHub Actions integration
Monitor scheduled GitHub Actions workflows with Drumbeats. Reusable workflow, ping wiring, and patterns for matrix and concurrent runs.
This guide shows how to wire Drumbeats into GitHub Actions workflows. By the end your scheduled workflows send start / success / failure pings automatically — no per-step copy-paste, no flaky steps that mask failures.
The patterns assume scheduled workflows (schedule: triggers). The same approach works for workflow_dispatch and repository_dispatch triggers; only the trigger metadata changes.
Quick example
The simplest pattern adds three curl steps to a workflow job:
name: Nightly sync
on:
schedule:
- cron: "0 2 * * *"
jobs:
sync:
runs-on: ubuntu-latest
env:
DRUMBEATS_MONITOR: 11111111-2222-3333-4444-555555555555
RUN_ID: "gh-${{ github.run_id }}"
steps:
- uses: actions/checkout@v4
- name: Drumbeats — start
run: curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/$DRUMBEATS_MONITOR/start?run_id=$RUN_ID"
- name: Run sync
id: sync
run: ./scripts/sync.sh
- name: Drumbeats — success
if: success()
run: curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/$DRUMBEATS_MONITOR/success?run_id=$RUN_ID"
- name: Drumbeats — failure
if: failure()
run: |
curl -sf --max-time 3 -X POST \
"https://api.drumbeats.io/v1/ping/$DRUMBEATS_MONITOR/failure?run_id=$RUN_ID" \
-H 'Content-Type: application/json' \
-d "$(jq -n --arg p "Workflow ${{ github.workflow }} failed at step ${{ github.action }}" '{payload: $p}')"name: Nightly sync
on:
schedule:
- cron: "0 2 * * *"
jobs:
sync:
runs-on: ubuntu-latest
env:
DRUMBEATS_MONITOR: 11111111-2222-3333-4444-555555555555
RUN_ID: "gh-${{ github.run_id }}"
steps:
- uses: actions/checkout@v4
- name: Drumbeats — start
run: curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/$DRUMBEATS_MONITOR/start?run_id=$RUN_ID"
- name: Run sync
id: sync
run: ./scripts/sync.sh
- name: Drumbeats — success
if: success()
run: curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/$DRUMBEATS_MONITOR/success?run_id=$RUN_ID"
- name: Drumbeats — failure
if: failure()
run: |
curl -sf --max-time 3 -X POST \
"https://api.drumbeats.io/v1/ping/$DRUMBEATS_MONITOR/failure?run_id=$RUN_ID" \
-H 'Content-Type: application/json' \
-d "$(jq -n --arg p "Workflow ${{ github.workflow }} failed at step ${{ github.action }}" '{payload: $p}')"if: success() / if: failure() ensure exactly one of the two final pings fires. github.run_id makes a stable run_id so the Drumbeats record links back to the workflow run.
Reusable workflow
For more than a couple of monitored workflows, hoist the pattern into a reusable workflow so each consumer is one line of YAML:
name: With Drumbeats
on:
workflow_call:
inputs:
monitor-id:
required: true
type: string
command:
required: true
type: string
jobs:
run:
runs-on: ubuntu-latest
env:
RUN_ID: "gh-${{ github.run_id }}-${{ github.run_attempt }}"
steps:
- uses: actions/checkout@v4
- name: Drumbeats — start
run: curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/${{ inputs.monitor-id }}/start?run_id=$RUN_ID"
- name: Run command
id: run
run: ${{ inputs.command }}
- name: Drumbeats — success
if: success()
run: curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/${{ inputs.monitor-id }}/success?run_id=$RUN_ID"
- name: Drumbeats — failure
if: failure()
run: curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/${{ inputs.monitor-id }}/failure?run_id=$RUN_ID"name: With Drumbeats
on:
workflow_call:
inputs:
monitor-id:
required: true
type: string
command:
required: true
type: string
jobs:
run:
runs-on: ubuntu-latest
env:
RUN_ID: "gh-${{ github.run_id }}-${{ github.run_attempt }}"
steps:
- uses: actions/checkout@v4
- name: Drumbeats — start
run: curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/${{ inputs.monitor-id }}/start?run_id=$RUN_ID"
- name: Run command
id: run
run: ${{ inputs.command }}
- name: Drumbeats — success
if: success()
run: curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/${{ inputs.monitor-id }}/success?run_id=$RUN_ID"
- name: Drumbeats — failure
if: failure()
run: curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/${{ inputs.monitor-id }}/failure?run_id=$RUN_ID"Consumer:
name: Nightly sync
on:
schedule:
- cron: "0 2 * * *"
jobs:
sync:
uses: ./.github/workflows/with-drumbeats.yml
with:
monitor-id: 11111111-2222-3333-4444-555555555555
command: ./scripts/sync.shname: Nightly sync
on:
schedule:
- cron: "0 2 * * *"
jobs:
sync:
uses: ./.github/workflows/with-drumbeats.yml
with:
monitor-id: 11111111-2222-3333-4444-555555555555
command: ./scripts/sync.shError handling
- Cancelled runs. A workflow cancelled by a user (or by
concurrency:cancellation) reports neithersuccessnorfailure— neitherif: success()norif: failure()fires. Drumbeats catches the hang viamax_duration_secondson the monitor. - Matrix jobs. Use a stable
run_idper matrix cell:"gh-${{ github.run_id }}-${{ matrix.target }}". Otherwise the matrix sends overlapping pings to the same monitor and Drumbeats can't correlate them. - Composite actions. Wrap the
actions/checkoutstep in the reusable workflow above and the consumer never sees it. Composite actions can also publish the ping logic — fine for repositories that vendor their own actions.
Production patterns
- Use
concurrency:to prevent overlapping runs. A nightly job that occasionally takes 90 minutes can collide with the next run.concurrency: { group: nightly-sync, cancel-in-progress: false }queues the second run instead. - Surface the failing step in the payload. Use
${{ github.action }}and${{ steps.run.outputs.* }}in the failure ping payload so the incident timeline points at the exact step. - GitHub Actions free minutes. Pings consume a beat each but no GitHub Actions minutes worth measuring — the
curlstep is sub-second. - Multi-environment via slug. Push staging and prod through the same workflow with
vars.DRUMBEATS_PROJECT_IDandvars.DRUMBEATS_SLUG, calling/v1/s-ping/<project>/<slug>/<event>instead of the monitor-ID endpoint. See Ping API: scheduled pings.
Related guides
- Monitor types — pick Cron for scheduled workflows; Event-driven for
workflow_dispatchtriggers. - Ping API — endpoint and parameter reference.
- Production hardening — retries, timeouts, observability patterns.
- Alternatives — how Drumbeats handles GitHub Actions monitoring vs Cronitor and Healthchecks.io.