# Set Up Crons | Sentry for Remix

Once implemented, it'll allow you to get alerts and metrics to help you solve errors, detect timeouts, and prevent disruptions to your service.

## [Requirements](https://docs.sentry.io/.md#requirements)

* Use our [getting started](https://docs.sentry.io/platforms/javascript/guides/remix.md) guide to install and configure the Sentry SDK (version `7.51.1` or newer) for your recurring job.
* [Create and configure](https://sentry.io/crons/create.md) your first Monitor.

Cron monitoring is only supported in Remix server-side

## [Automatic Crons Instrumentation](https://docs.sentry.io/.md#automatic-crons-instrumentation)

If you're using the [`cron`](https://www.npmjs.com/package/cron.md), [`node-cron`](https://www.npmjs.com/package/node-cron.md) or [`node-schedule`](https://www.npmjs.com/package/node-schedule.md) libraries to run your periodic tasks, you can use our instrumentation functions in the `Sentry.cron` export to monitor your cron jobs.

### [Cron](https://docs.sentry.io/.md#cron)

Requires SDK version `7.92.0` or higher.

Use `Sentry.cron.instrumentCron` to instrument the `CronJob` constructor or `CronJob.from` method in the [`cron`](https://www.npmjs.com/package/cron.md) library. Pass the name of the cron monitor as a second argument to the function.

```JavaScript
import { CronJob } from "cron";

const CronJobWithCheckIn = Sentry.cron.instrumentCron(CronJob, "my-cron-job");

// use the constructor
const job = new CronJobWithCheckIn("* * * * *", () => {
  console.log("You will see this message every minute");
});

// or from method
const job = CronJobWithCheckIn.from({
  cronTime: "* * * * *",
  onTick: () => {
    console.log("You will see this message every minute");
  },
});
```

### [Node Cron](https://docs.sentry.io/.md#node-cron)

Requires SDK version `7.92.0` or higher.

Use `Sentry.cron.instrumentNodeCron` to instrument the `cron` export from the [`node-cron`](https://www.npmjs.com/package/node-cron.md) library. This returns an object with the same API as the original `cron` export, but with the `schedule` method instrumented. You can pass the name of the cron monitor and an optional time zone as part of the third options argument to the function.

```JavaScript
import cron from "node-cron";

const cronWithCheckIn = Sentry.cron.instrumentNodeCron(cron);

cronWithCheckIn.schedule(
  "* * * * *",
  () => {
    console.log("running a task every minute");
  },
  { name: "my-cron-job" }
);
```

### [Node Schedule](https://docs.sentry.io/.md#node-schedule)

Requires SDK version `7.93.0` or higher.

Use `Sentry.cron.instrumentNodeSchedule` to instrument the `schedule` export from the [`node-schedule`](https://www.npmjs.com/package/node-schedule.md) library. This returns an object with the same API as the original `schedule` export, but with the `scheduleJob` method instrumented. You can pass the name of the cron job as the first argument to the function. Currently this only supports cronstring as the second argument to `scheduleJob`.

```JavaScript
import * as schedule from "node-schedule";

const scheduleWithCheckIn = Sentry.cron.instrumentNodeSchedule(schedule);

scheduleWithCheckIn.scheduleJob(
  "my-cron-job",
  "* * * * *",
  () => {
    console.log("running a task every minute");
  }
);
```

## [Job Monitoring](https://docs.sentry.io/.md#job-monitoring)

Use the `Sentry.withMonitor()` API to monitor a callback and notify you if your periodic task is missed (or doesn't start when expected), if it fails due to a problem in the runtime (such as an error), or if it fails by exceeding its maximum runtime.

`Sentry.withMonitor()` requires SDK version `7.76.0`.

```javascript
Sentry.withMonitor("<monitor-slug>", () => {
  // Execute your scheduled task here...
});
```

If you are using an SDK version prior to `7.76.0`, you can use the `Sentry.captureCheckIn()` API documented below.

## [Check-Ins](https://docs.sentry.io/.md#check-ins)

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).

```javascript
// 🟡 Notify Sentry your job is running:
const checkInId = Sentry.captureCheckIn({
  monitorSlug: "<monitor-slug>",
  status: "in_progress",
});

// Execute your scheduled task here...

// 🟢 Notify Sentry your job has completed successfully:
Sentry.captureCheckIn({
  // Make sure this variable is named `checkInId`
  checkInId,
  monitorSlug: "<monitor-slug>",
  status: "ok",
});
```

If your job execution fails, you can notify Sentry about the failure:

```javascript
// 🔴 Notify Sentry your job has failed:
Sentry.captureCheckIn({
  // Make sure this variable is named `checkInId`
  checkInId,
  monitorSlug: "<monitor-slug>",
  status: "error",
});
```

## [Heartbeat](https://docs.sentry.io/.md#heartbeat)

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.

```javascript
// Execute your scheduled task...

// 🟢 Notify Sentry your job completed successfully:
Sentry.captureCheckIn({
  monitorSlug: "<monitor-slug>",
  status: "ok",
});
```

If your job execution fails, you can:

```javascript
// 🔴 Notify Sentry your job has failed:
Sentry.captureCheckIn({
  monitorSlug: "<monitor-slug>",
  status: "error",
});
```

## [Upserting Cron Monitors](https://docs.sentry.io/.md#upserting-cron-monitors)

You can create and update your Monitors programmatically with code rather than [creating and configuring them in Sentry.io](https://sentry.io/crons/create.md).

To create/update a monitor, use `Sentry.withMonitor()` and pass in your monitor configuration as a third parameter:

```javascript
const monitorConfig = {
  schedule: {
    type: "crontab",
    value: "* * * * *",
  },
  checkinMargin: 2, // In minutes. Optional.
  maxRuntime: 10, // In minutes. Optional.
  timezone: "America/Los_Angeles", // Optional.
};

Sentry.withMonitor(
  "<monitor-slug>",
  () => {
    // Execute your scheduled task here...
  },
  monitorConfig,
);
```

To configure the monitor's check-ins, use `Sentry.captureCheckIn()` and pass in your monitor configuration as a second parameter:

```javascript
const monitorConfig = {
  schedule: {
    type: "crontab",
    value: "* * * * *",
  },
  checkinMargin: 2, // In minutes. Optional.
  maxRuntime: 10, // In minutes. Optional.
  timezone: "America/Los_Angeles", // Optional.
};

// 🟡 Notify Sentry your job is running:
const checkInId = Sentry.captureCheckIn(
  {
    monitorSlug: "<monitor-slug>",
    status: "in_progress",
  },
  monitorConfig,
);

// Execute your scheduled task here...

// 🟢 Notify Sentry your job has completed successfully:
Sentry.captureCheckIn(
  {
    // Make sure this variable is named `checkInId`
    checkInId,
    monitorSlug: "<monitor-slug>",
    status: "ok",
  },
  monitorConfig,
);
```

### [Monitor Configuration Properties](https://docs.sentry.io/.md#monitor-configuration-properties)

The following are available monitor configuration properties:

`schedule`:

The job's schedule:

The schedule representation for your monitor, either `crontab` or `interval`. The structure will vary depending on the type:

```json
{"type": "crontab", "value": "0 * * * *"}
{"type": "interval", "value": "2", "unit": "hour"}
```

`checkinMargin`:

The amount of time (in minutes) Sentry should wait for your check-in before it's considered missed ("grace period"). Optional.

We recommend that your check-in margin be less than or equal to your interval.

`maxRuntime`:

The amount of time (in minutes) your job is allowed to run before it's considered failed. Optional.

`timezone`:

The `tz` where your job is running. This is usually your server's timezone, (such as `America/Los_Angeles`). See [list of tz database time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones.md). Optional.

`node-cron` allows you to pass luxon timezones, but you have to convert them to an IANA timezone when using Sentry (for example, using `DateTime.local().zoneName`).

`failureIssueThreshold`:

*requires SDK version `8.7.0` or higher*

The number of consecutive failed check-ins required before an issue can be created. Optional.

`recoveryThreshold`:

*requires SDK version `8.7.0` or higher*

The number of consecutive successful check-ins required for an issue to be considered resolved. Optional.

## [Alerts](https://docs.sentry.io/.md#alerts)

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:

1. Navigate to **Alerts** in the sidebar.
2. Create a new alert and select "Issues" under "Errors" as the alert type.
3. 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`

[![Cron completed alert filter](https://docs.sentry.io/_next/image/?url=%2Fmdx-images%2Fcrons-alerts-example-CJJAWX24.png%231956x1084\&w=3840\&q=75)](https://docs.sentry.io/mdx-images/crons-alerts-example-CJJAWX24.png)

Learn more in [Issue Alert Configuration](https://docs.sentry.io/product/alerts/create-alerts/issue-alert-config.md).

## [Rate Limits](https://docs.sentry.io/.md#rate-limits)

Crons imposes a rate limit on check-ins to prevent abuse and resource overuse. Specifically, you can only send a maximum of **6 check-ins per minute per existing monitor environment**. This limit is enforced on a per-project basis, meaning that the rate limit applies collectively to all monitor environments within a given project. You can check if any of your check-ins are being dropped in the [Usage Stats](https://docs.sentry.io/product/stats.md#usage-stats) page.

To avoid dropped check-ins, it is crucial to manage and distribute your check-ins efficiently within the rate limits. This will help maintain accurate monitoring and ensure that all critical check-ins are captured and processed.
