Set Up Crons for Fiber
Learn how to set up Crons with the Go SDK to monitor the uptime and performance of any scheduled, recurring job in your application.
Once implemented, it'll allow you to get alerts and metrics to help you solve errors, detect timeouts, and prevent disruptions to your service.
- Use our getting started guide to install and configure the Sentry Go SDK (version
0.23.0or newer) for your recurring job. - Send a monitor configuration from your code as shown below, and Sentry creates the monitor on the first check-in. You can also create the monitor in Sentry instead.
Check-in monitoring allows you to track a job's progress by completing two check-ins: one at the start of your job and another at the end of your job. This two-step process allows Sentry to notify you if your job didn't start when expected (missed) or if it exceeded its maximum runtime (failed).
Wrap your job with sentry.WithMonitor. It sends an in-progress check-in with the monitor config, which creates or updates the monitor, then runs the job and sends an ok or error check-in with its duration:
err := sentry.WithMonitor("<monitor-slug>", &sentry.MonitorConfig{
Schedule: sentry.CrontabSchedule("0 * * * *"),
}, func() error {
// Execute your scheduled task here...
return nil
})
err := sentry.WithMonitor("<monitor-slug>", &sentry.MonitorConfig{
Schedule: sentry.CrontabSchedule("0 * * * *"),
}, func() error {
// Execute your scheduled task here...
return nil
})
The job's error is returned unchanged. If the job panics, Sentry gets an error check-in and the panic continues. sentry.WithMonitor and sentrycron require sentry-go version 0.50.0 or higher. If the monitor already exists in Sentry, you can pass nil instead of a config.
If you schedule jobs with robfig/cron, add them with sentrycron.AddFunc. Install the package:
go get github.com/getsentry/sentry-go/cron
go get github.com/getsentry/sentry-go/cron
It wraps the job in sentry.WithMonitor and uses the job's spec as the monitor schedule and the cron's location as its timezone:
import (
"time"
"github.com/getsentry/sentry-go"
sentrycron "github.com/getsentry/sentry-go/cron"
"github.com/robfig/cron/v3"
)
c := cron.New(cron.WithLocation(time.UTC))
sentrycron.AddFunc(c, "0 * * * *", "<monitor-slug>", func() error {
// Execute your scheduled task here...
return nil
}, &sentry.MonitorConfig{MaxRuntime: 30})
c.Start()
import (
"time"
"github.com/getsentry/sentry-go"
sentrycron "github.com/getsentry/sentry-go/cron"
"github.com/robfig/cron/v3"
)
c := cron.New(cron.WithLocation(time.UTC))
sentrycron.AddFunc(c, "0 * * * *", "<monitor-slug>", func() error {
// Execute your scheduled task here...
return nil
}, &sentry.MonitorConfig{MaxRuntime: 30})
c.Start()
Pass nil as the last argument to use the default monitor settings. Specs Sentry can't represent, such as seconds other than a fixed value or @every under a minute, still send check-ins but don't create the monitor.
With the default time.Local location, the timezone comes from $TZ or /etc/localtime. If that isn't an IANA name, such as America/New_York, only check-ins are sent, so set the schedule in Sentry or use cron.WithLocation.
To send check-ins yourself, call sentry.CaptureCheckIn at the start and end of your job. Pass a monitor config with the in-progress check-in so Sentry creates or updates the monitor from your code:
monitorConfig := &sentry.MonitorConfig{
Schedule: sentry.CrontabSchedule("0 * * * *"),
}
// 🟡 Notify Sentry your job is running:
checkinId := sentry.CaptureCheckIn(
&sentry.CheckIn{
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusInProgress,
},
monitorConfig,
)
// Execute your scheduled task here...
// 🟢 Notify Sentry your job has completed successfully:
sentry.CaptureCheckIn(
&sentry.CheckIn{
ID: *checkinId,
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusOK,
},
monitorConfig,
)
monitorConfig := &sentry.MonitorConfig{
Schedule: sentry.CrontabSchedule("0 * * * *"),
}
// 🟡 Notify Sentry your job is running:
checkinId := sentry.CaptureCheckIn(
&sentry.CheckIn{
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusInProgress,
},
monitorConfig,
)
// Execute your scheduled task here...
// 🟢 Notify Sentry your job has completed successfully:
sentry.CaptureCheckIn(
&sentry.CheckIn{
ID: *checkinId,
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusOK,
},
monitorConfig,
)
If the monitor already exists in Sentry, the configuration is optional, so you can pass nil instead. See Upserting Cron Monitors for all configuration options.
If your job execution fails, you can notify Sentry about the failure:
// 🔴 Notify Sentry your job has failed:
sentry.CaptureCheckIn(
&sentry.CheckIn{
ID: *checkinId,
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusError,
},
nil,
)
// 🔴 Notify Sentry your job has failed:
sentry.CaptureCheckIn(
&sentry.CheckIn{
ID: *checkinId,
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusError,
},
nil,
)
Heartbeat monitoring notifies Sentry of a job's status through one check-in. This setup will only notify you if your job didn't start when expected (missed). If you need to track a job to see if it exceeded its maximum runtime (failed), use check-ins instead.
// Execute your scheduled task...
// 🟢 Notify Sentry your job completed successfully:
sentry.CaptureCheckIn(
&sentry.CheckIn{
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusOK,
// Specify the duration of the job.
Duration: time.Second * 10,
},
nil,
)
// Execute your scheduled task...
// 🟢 Notify Sentry your job completed successfully:
sentry.CaptureCheckIn(
&sentry.CheckIn{
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusOK,
// Specify the duration of the job.
Duration: time.Second * 10,
},
nil,
)
If your job execution fails, you can:
// 🔴 Notify Sentry your job has failed:
sentry.CaptureCheckIn(
&sentry.CheckIn{
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusError,
Duration: time.Second * 10,
},
nil,
)
// 🔴 Notify Sentry your job has failed:
sentry.CaptureCheckIn(
&sentry.CheckIn{
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusError,
Duration: time.Second * 10,
},
nil,
)
You can create and update your Monitors programmatically with code rather than creating and configuring them in Sentry.io.
// Create a crontab schedule object (every 10 minutes)
monitorSchedule := sentry.CrontabSchedule("*/10 * * * *")
// Or create an interval schedule object (every 10 minutes)
monitorSchedule := sentry.IntervalSchedule(10, sentry.MonitorScheduleUnitMinute)
// Create a crontab schedule object (every 10 minutes)
monitorSchedule := sentry.CrontabSchedule("*/10 * * * *")
// Or create an interval schedule object (every 10 minutes)
monitorSchedule := sentry.IntervalSchedule(10, sentry.MonitorScheduleUnitMinute)
Supported units are:
sentry.MonitorScheduleUnitMinutesentry.MonitorScheduleUnitHoursentry.MonitorScheduleUnitDaysentry.MonitorScheduleUnitWeeksentry.MonitorScheduleUnitMonthsentry.MonitorScheduleUnitYear
// Create a monitor config object
monitorConfig := &sentry.MonitorConfig{
Schedule: monitorSchedule,
MaxRuntime: 2,
CheckInMargin: 1,
FailureIssueThreshold: 2,
}
// 🟡 Notify Sentry your job is running:
checkinId := sentry.CaptureCheckIn(
&sentry.CheckIn{
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusInProgress,
},
monitorConfig,
)
// Execute your scheduled task here...
// 🟢 Notify Sentry your job has completed successfully:
sentry.CaptureCheckIn(
&sentry.CheckIn{
ID: *checkinId,
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusOK,
},
monitorConfig,
)
// Create a monitor config object
monitorConfig := &sentry.MonitorConfig{
Schedule: monitorSchedule,
MaxRuntime: 2,
CheckInMargin: 1,
FailureIssueThreshold: 2,
}
// 🟡 Notify Sentry your job is running:
checkinId := sentry.CaptureCheckIn(
&sentry.CheckIn{
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusInProgress,
},
monitorConfig,
)
// Execute your scheduled task here...
// 🟢 Notify Sentry your job has completed successfully:
sentry.CaptureCheckIn(
&sentry.CheckIn{
ID: *checkinId,
MonitorSlug: "<monitor-slug>",
Status: sentry.CheckInStatusOK,
},
monitorConfig,
)
A full end-to-end example can be found in the sentry-go repository.
To link any exceptions captured during your job's lifecycle, use Sentry's context with your monitor slug.
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetContext("monitor", sentry.Context{"slug": "<monitor-slug>"})
})
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetContext("monitor", sentry.Context{"slug": "<monitor-slug>"})
})
When your recurring job fails to check in (missed), runs beyond its configured maximum runtime (failed), or manually reports a failure, Sentry will create an error event with a tag to your monitor.
To receive alerts about these events:
- Navigate to Alerts in the sidebar.
- Create a new alert and select "Issues" under "Errors" as the alert type.
- Configure your alert and define a filter match to use:
The event's tags match {key} {match} {value}.
Example: The event's tags match monitor.slug equals my-monitor-slug-here
Learn more in Alerts.
To prevent abuse and resource overuse, Crons limits check-ins to 6 per minute for each monitor environment.
For example, if you have a monitor called "database-backup" with two environments:
database-backupin environmentproductioncan send up to 6 check-ins per minutedatabase-backupin environmentstagingcan also send up to 6 check-ins per minute- Combined, they can send up to 12 check-ins per minute
You can verify if any check-ins are being dropped by visiting the Usage Stats page. To avoid dropped check-ins, ensure your monitors don't exceed the rate limit.
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").