GTM engineering field note

How I Monitor GTM Automations GitHub Actions Silently Skips

A practical monitoring pattern for scheduled GTM automations: expected-run registries, timelines, missed-run detection, safe replays, and actionable alerts.

Published 2026-08-08 · Updated 2026-08-08 · By Vikas Pareek

A success alert cannot tell you what never started

I moved several scheduled GTM automations to GitHub Actions: account-scoring refreshes, engagement-intent reports, BDR performance tracking, outreach-gap detection, and intelligence extraction.

The setup had attractive properties. Workflow files lived beside the code. Secrets, logs, and manual dispatch were available. The compute was practical for daily jobs.

Then I compared thirty days of expected schedules with actual run history. Median start delays across workflows ranged from 47 minutes to three hours. The worst case was more than four hours late. Another daily schedule had run only twice in six weeks.

Every job posted to Slack, but Slack was a newspaper. I was reading the channel and hoping I noticed which expected story never appeared.

The operational question was simpler: did everything that should run today actually run?

Scheduled does not mean exact

GitHub's workflow troubleshooting documentation states that scheduled events can be delayed during high load, especially around the start of the hour, and that sufficiently loaded queues may drop jobs. GitHub also documents that scheduled workflows in public repositories can be automatically disabled after 60 days without repository activity.

Those behaviours are acceptable for many maintenance tasks. They become material when a revenue team assumes a score, report, or action queue is fresh.

Instead of demanding perfect scheduling from a best-effort system, define an acceptable window and monitor the business expectation independently.

Build an expected-run registry

Monitoring begins with what should happen.

For every job, store:

This registry lets one monitor compare GitHub Actions, n8n, Trigger.dev, and custom services without pretending they expose identical APIs.

Use five states, not pass or fail

My day timeline uses operational states that answer different questions.

Upcoming

The expected window has not started. No action is required.

Running

The runtime reports an active execution. Track start time and expected duration.

Completed

The correct job completed inside the accepted window. Store the run link, commit, conclusion, and relevant output metadata.

Failed

A run started and returned a failure, cancellation, or invalid result. The runtime usually has logs for this state.

Missing or late

The expected start window passed and no matching run exists. This is the state that success alerts cannot detect.

Keep “late but running” separate from “never started” when the business consequence differs.

Match runs carefully

Do not identify a run only by workflow display name. Names change and repositories can contain similarly named jobs.

Use stable repository and workflow identifiers, the expected schedule window, event type, branch, and run creation time. Ignore manual or push-triggered runs unless they satisfy the same business job and output contract.

Store timestamps in UTC and convert for display. Daylight-saving changes and local-midnight boundaries can otherwise create false missing-run alerts.

Add safe recovery

My monitor includes one-click rerun or dispatch for eligible failures and missed starts. That convenience requires design work inside the job.

A replay-safe workflow should:

Do not automatically replay workflows that send customer messages, mutate financial records, or can duplicate irreversible work. Alert a human with the required context instead.

Give the debugger usable context

A “workflow failed” message transfers investigation work to the operator. A useful alert contains:

My dashboard includes a copy-context action so I can bring failure logs and metadata into a coding session without manually reconstructing the incident.

Sanitise secrets and customer data before making logs copyable or posting them into Slack.

Use an independent watchdog

The system checking a scheduler should not depend solely on the same scheduler.

I use a separate n8n watchdog that checks expected jobs every fifteen minutes. When a safe GitHub workflow is missing, it can dispatch the job and post that it recovered a real missed run. The watchdog caught one on its first tick.

For critical workflows, separate the monitor's runtime, credentials, and alert path from the jobs it observes. The degree of independence should match the business impact.

Monitor data freshness too

A green runtime conclusion does not guarantee a useful business output.

Add checks such as:

A workflow can complete successfully after reading stale input or writing zero records. Operational and data-quality checks belong together.

Measure the reliability system

Track:

Use the trends to fix root causes. Shift schedules away from crowded boundaries, improve API retries, rotate credentials before expiry, or move exact-time critical jobs to a scheduler with stronger guarantees.

Start with a simple daily table

You do not need a custom application on day one. A registry, a script that queries run history, and a table of expected versus observed jobs can expose the problem.

Add the timeline, re-run controls, and cross-runtime adapters after the comparison proves useful. The most important architectural move is switching from event observation to expectation monitoring.

This pattern applies beyond GitHub Actions. Every production n8n GTM workflow and AI GTM system needs a way to answer what should have happened, what actually happened, and who owns the difference.