---
title: "Crons"
description: "Sentry Crons allows you to monitor the uptime and performance of any scheduled, recurring job in your application using the Sentry PHP SDK."
url: https://docs.sentry.io/platforms/php/guides/symfony/crons/
---

# Set Up Crons for Symfony

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/platforms/php/guides/symfony/crons.md#requirements)

* Use our [getting started](https://docs.sentry.io/platforms/php/guides/symfony.md) guide to install and configure the Sentry PHP SDK (min v3.16.0) 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](https://sentry.io/issues/alerts/new/crons/) instead.

## [Check-Ins (Recommended)](https://docs.sentry.io/platforms/php/guides/symfony/crons.md#check-ins-recommended)

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

Use `withMonitor()` to wrap your job. It sends an `in-progress` check-in, then an `ok` or `error` check-in depending on whether your callback threw an exception. Pass a monitor configuration so Sentry creates or updates the monitor from your code:

```php
\Sentry\withMonitor(
    slug: '<monitor-slug>',
    callback: fn () => doSomething(),
    monitorConfig: new \Sentry\MonitorConfig(\Sentry\MonitorSchedule::crontab('0 * * * *')),
);
```

If the monitor already exists in Sentry, the configuration is optional. See [Upserting Cron Monitors](https://docs.sentry.io/platforms/php/guides/symfony/crons.md#upserting-cron-monitors) for all configuration options.

You can also send the check-ins manually:

```php
// 🟡 Notify Sentry your job is running:
$checkInId = \Sentry\captureCheckIn(
    slug: '<monitor-slug>',
    status: CheckInStatus::inProgress()
);

// Execute your scheduled task here...

// 🟢 Notify Sentry your job has completed successfully:
\Sentry\captureCheckIn(
    slug: '<monitor-slug>',
    status: CheckInStatus::ok(),
    checkInId: $checkInId,
);
```

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

```php
// 🔴 Notify Sentry your job has failed:
\Sentry\captureCheckIn(
    slug: '<monitor-slug>',
    status: CheckInStatus::error(),
    checkInId: $checkInId,
);
```

## [Heartbeat](https://docs.sentry.io/platforms/php/guides/symfony/crons.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.

```php
// Execute your scheduled task...

// 🟢 Notify Sentry your job completed successfully:
\Sentry\captureCheckIn(
    slug: '<monitor-slug>',
    status: CheckInStatus::ok(),
    duration: 10, // Optional duration in seconds
);
```

If your job execution fails, you can:

```php
// 🔴 Notify Sentry your job has failed:
\Sentry\captureCheckIn(
    slug: '<monitor-slug>',
    status: CheckInStatus::error(),
    duration: 10, // Optional duration in seconds
);
```

## [Upserting Cron Monitors](https://docs.sentry.io/platforms/php/guides/symfony/crons.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/issues/alerts/new/crons/).

```php
// Create a crontab schedule object (every 10 minutes)
$monitorSchedule = \Sentry\MonitorSchedule::crontab('*/10 * * * *');

// Or create an interval schedule object (every 10 minutes)
$monitorSchedule = \Sentry\MonitorSchedule::interval(10, MonitorScheduleUnit::minute());
```

Supported units are:

* `MonitorScheduleUnit::minute()`
* `MonitorScheduleUnit::hour()`
* `MonitorScheduleUnit::day()`
* `MonitorScheduleUnit::week()`
* `MonitorScheduleUnit::month()`
* `MonitorScheduleUnit::year()`

```php
// Create a config object
$monitorConfig = new \Sentry\MonitorConfig(
    $monitorSchedule,
    checkinMargin: 5, // Optional check-in margin in minutes
    maxRuntime: 15, // Optional max runtime in minutes
    timezone: 'Europe/Vienna', // Optional timezone, defaults to UTC. Set this to your servers timezone
    failureIssueThreshold: 2, //Optional failure issue threshold
    recoveryThreshold: 5 // Optional recovery threshold
);

// 🟡 Notify Sentry your job is running:
$checkInId = \Sentry\captureCheckIn(
    slug: '<monitor-slug>',
    status: CheckInStatus::inProgress(),
    monitorConfig: $monitorConfig,
);

// Execute your scheduled task here...

// 🟢 Notify Sentry your job has completed successfully:
\Sentry\captureCheckIn(
    slug: '<monitor-slug>',
    status: CheckInStatus::ok(),
    checkInId: $checkInId,
);
```

## [Alerts](https://docs.sentry.io/platforms/php/guides/symfony/crons.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`

Learn more in [Alerts](https://docs.sentry.io/product/monitors-and-alerts/alerts.md).

## [Rate Limits](https://docs.sentry.io/platforms/php/guides/symfony/crons.md#rate-limits)

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-backup` in environment `production` can send up to 6 check-ins per minute
* `database-backup` in environment `staging` can 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](https://docs.sentry.io/product/stats.md#usage-stats) page. To avoid dropped check-ins, ensure your monitors don't exceed the rate limit.
