fix: GitHub Actions workflow failing to send heartbeat notification

You've painstakingly set up a critical scheduled job in GitHub Actions. Maybe it's a daily data sync, a weekly report generation, or a monthly cleanup script. You've even implemented a heartbeat notification, diligently sending a curl request to your monitoring service (like Heartfly) at the end of the job. You think you're safe.

Then, one day, you check your dashboards, and something's off. Data is stale, reports are missing. Panic sets in. You rush to the GitHub Actions logs, only to discover your workflow didn't run at all, or it failed silently somewhere along the way. And the worst part? Your monitoring system never alerted you. The heartbeat notification, the very mechanism designed to prevent silent failures, also failed.

This is a frustrating, yet common, scenario. In this article, we'll dive deep into why your GitHub Actions workflow might be failing to send those crucial heartbeat notifications and, more importantly, how to fix it with robust, production-ready patterns.

The Silent Failure: Why Your Monitoring Might Be Missing

A heartbeat notification is a simple concept: a scheduled job "pings" a monitoring service when it successfully completes (or sometimes when it starts or fails). If the monitoring service doesn't receive this ping within an expected interval, it assumes the job failed or didn't run and alerts you. It's a powerful "dead man's switch" for scheduled tasks.

When this system breaks, it's often due to one of several common culprits, usually stemming from an incomplete understanding of GitHub Actions' execution model or a lack of robust error handling. The core problem is that if the step responsible for sending the heartbeat fails, or is never reached, your monitoring system remains blissfully unaware that something is wrong.

Unmasking the Culprits: Common Reasons for Missed Heartbeats

Before we look at code, let's list the most frequent reasons why your GitHub Actions heartbeats might be going unheard:

  • Workflow Logic Errors:
    • Incorrect if: conditions: The heartbeat step might be conditionally executed and the condition isn't met (e.g., if: success() when a preceding step actually failed).
    • Step order: The heartbeat is placed before a critical step that might fail, preventing the heartbeat from being sent if that step crashes.
    • Early exits: A script or command within a step exits prematurely without a non-zero status code, or the workflow exits before reaching the heartbeat step.
  • Environment Variable / Secret Issues:
    • **Missing `HEARTBEAT_