How to Monitor Cron Jobs in Go with Cronaman
The silent failure problem
Go services often ship with built-in schedulers — goroutines that wake on a ticker, or jobs managed by robfig/cron. They're lightweight, easy to deploy, and completely invisible when they fail.
A panic in a goroutine that isn't recovered will silently kill just that goroutine while the rest of your service keeps running. A job that returns an error with no alerting path might log a line and keep moving. Days later you discover a critical sync stopped working — because nothing told you it failed.
What is heartbeat monitoring?
Heartbeat monitoring adds an external watchdog to your jobs. You configure an expected interval in Cronaman, and your job sends a simple HTTP ping at the end of every successful execution. If that ping doesn't arrive within the window, Cronaman alerts you.
Go's net/http package handles everything. No third-party SDK, no new dependencies.
Create a Cronaman monitor
Before writing any code, create a monitor in Cronaman:
- Sign up at cronaman.dev — free plan, no credit card required
- Click New Monitor
- Name it (e.g., "Data sync") and set the interval to match your job's schedule
- Copy your unique ping URL:
https://cronaman.dev/ping/data-sync
Ping Cronaman with net/http
A small helper function handles the ping and swallows network errors so they never mask the real job error:
package main
import (
"context"
"fmt"
"net/http"
"time"
)
const (
pingURL = "https://cronaman.dev/ping/data-sync"
failURL = "https://cronaman.dev/ping/data-sync/fail"
)
var httpClient = &http.Client{Timeout: 10 * time.Second}
func pingCronaman(url string) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
resp, err := httpClient.Do(req)
if err != nil {
return // don't let a network error mask the job result
}
resp.Body.Close()
}
func runDataSync() error {
// Your job logic here
fmt.Println("Syncing data...")
return nil
}
func job() {
if err := runDataSync(); err != nil {
fmt.Printf("job failed: %v\n", err)
pingCronaman(failURL) // signal failure immediately
return
}
pingCronaman(pingURL) // signal success
}A few details worth noting:
- Always set a
Timeouton the HTTP client — Go's default client has no timeout and will block indefinitely - Reuse a single
http.Clientacross calls to take advantage of connection pooling - Always close
resp.Bodyeven when you don't read it — otherwise connections leak
Integration with robfig/cron
If you use robfig/cron to schedule jobs inside your Go service, wrap your job function so the ping is always paired with the actual work:
package main
import (
"fmt"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New()
c.AddFunc("0 2 * * *", func() { // daily at 02:00
if err := runDataSync(); err != nil {
fmt.Printf("data sync failed: %v\n", err)
pingCronaman(failURL)
return
}
pingCronaman(pingURL)
})
c.Start()
// block forever
select {}
}Each cron.AddFunc callback runs in its own goroutine. Panics in that goroutine don't propagate to the scheduler, so wrap critical jobs with a recover to ensure the fail ping still fires:
c.AddFunc("0 2 * * *", func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("panic in data sync: %v\n", r)
pingCronaman(failURL)
}
}()
if err := runDataSync(); err != nil {
fmt.Printf("data sync failed: %v\n", err)
pingCronaman(failURL)
return
}
pingCronaman(pingURL)
})Verify your setup
Call the job function directly from a test or main to confirm the ping fires:
go run . --run-job-onceOpen your Cronaman dashboard. Within a few seconds the monitor should show "healthy" with a "Last ping" timestamp. If it stays grey, verify outbound HTTPS from your host:
curl -v https://cronaman.dev/ping/data-syncMore cron monitoring guides
Using a different stack? The same heartbeat pattern works everywhere:
- How to Monitor Cron Jobs in Python — covers urllib and the requests library
- How to Monitor Cron Jobs in Node.js — covers native fetch, Axios, and node-cron
- How to Monitor Cron Jobs in Bash — covers shell scripts and the crontab && curl pattern
More guides
What Is Cron Job Monitoring? (And Why You Need It)
5 min readProBeyond Timing: Catch Silent Successes with Semantic Ping Payloads
5 min readPythonHow to Monitor Cron Jobs in Python with Cronaman
6 min readNode.jsHow to Monitor Cron Jobs in Node.js with Cronaman
7 min readPHPHow to Monitor Cron Jobs in PHP with Cronaman
6 min readBashHow to Monitor Cron Jobs in Bash with Cronaman
5 min readRubyHow to Monitor Cron Jobs in Ruby with Cronaman
6 min readLaravelHow to Monitor Laravel Cron Jobs with Cronaman
6 min readStart monitoring your Go cron jobs
Free forever for up to 3 monitors. No credit card required. Set up in under 2 minutes.
Start monitoring free