# Scheduled Discovery

Source: https://docs.ops0.com/docs/discovery/scheduling

Automate discovery scans on a recurring schedule using cron expressions. Scheduled discovery eliminates manual rescans and ensures continuous visibility into your cloud infrastructure.

## How Scheduling Works

ops0 stores your scan configuration — provider, integration, regions, resource types, and scope — and re-runs it at the configured interval. Each scheduled run creates a new discovery session, giving you a timestamped snapshot you can compare, trend, and audit over time.

---

## Creating a Schedule

### Open Discovery Schedules
Navigate to **Discovery → Schedules** and click **New Schedule**.

### Select Provider and Integration
Choose the cloud provider (AWS, GCP, Azure, or Oracle) and the cloud integration to use for scanning.

### Configure Scope
Set the scan mode (single account, organization, selected accounts), regions, and resource types — the same options available in the Discovery Wizard.

### Set the Cron Expression
Enter a cron expression for when to run, or pick from the preset options.

### Enable and Save
Toggle the schedule on and save. The first run fires at the next matching cron time.

---

## Cron Expression Reference

Schedules use standard 5-field cron syntax: `minute hour day-of-month month day-of-week`.

| Expression | When It Runs | Best For |
|------------|-------------|----------|
| `0 2 * * *` | Daily at 2:00 AM | Daily drift monitoring |
| `0 */6 * * *` | Every 6 hours | Critical production environments |
| `0 0 * * 1` | Every Monday at midnight | Weekly compliance audits |
| `0 0 1 * *` | 1st of each month at midnight | Monthly cost reporting |
| `0 9 * * 1-5` | Weekdays at 9:00 AM | Business-hours monitoring |
| `30 1 * * *` | Daily at 1:30 AM | Offset to avoid API throttling |

**Timezone**

All cron expressions run in UTC. Convert your target local time to UTC when writing expressions.

---

## Managing Schedules

The Schedules list shows every configured schedule across your organization:

| Column | Description |
|--------|-------------|
| **Name** | Human-readable label for the schedule |
| **Provider** | Cloud provider being scanned |
| **Integration** | Cloud account / credentials used |
| **Frequency** | Cron expression |
| **Last Run** | Timestamp of the most recent execution |
| **Next Run** | Calculated next fire time |
| **Status** | Enabled or Disabled |

### Schedule Actions

| Action | Description |
|--------|-------------|
| **Enable / Disable** | Pause and resume without losing configuration |
| **Edit** | Update cron expression, regions, or resource types |
| **Run Now** | Trigger an immediate scan outside the schedule |
| **View History** | See all sessions created by this schedule |
| **Delete** | Remove the schedule permanently |

---

## Automatic Session Comparison

When a scheduled scan completes, ops0 can automatically compare the new session against the previous one for the same integration. This is the fastest way to catch infrastructure drift without any manual steps.

Comparison results are stored and visible at **Discovery → Compare**, with:
- Resources added since the last scan
- Resources removed since the last scan
- Resources with configuration changes
- Cost delta (estimated monthly cost change)
- Security regressions (new findings from security scanning)

See [Drift Detection](https://docs.ops0.com/docs/discovery/drift-detection) for details on interpreting comparison results.

---

## Baseline Pinning

Beyond automatic comparison against the previous session, you can pin any session as a named baseline:

### Open a Completed Session
Navigate to the session you want to use as your baseline.

### Save as Baseline
Click **Save as Baseline** and give it a name (e.g., "Post-Q2-Audit" or "Clean-Production").

### Compare Against It
When running a new scan or viewing the Schedules page, select the named baseline as the comparison target instead of the most recent session.

This is useful for:
- Maintaining a "gold standard" snapshot after a compliance audit
- Comparing against a pre-migration state when migrating resources to IaC
- Tracking drift from a known-good configuration over a long period

---

## Example: Daily Production Monitoring

### Goal

Detect unauthorized changes in the production AWS account within 24 hours and surface cost changes.

### Configuration

| Setting | Value |
|---------|-------|
| **Name** | `daily-production-scan` |
| **Provider** | AWS |
| **Integration** | AWS Production (account 123456789012) |
| **Scan Mode** | Single Account |
| **Regions** | us-east-1, us-west-2 |
| **Resource Types** | EC2, VPC, RDS, S3, Security Groups, IAM |
| **Cron** | `0 2 * * *` |
| **Auto-compare** | Enabled (previous session) |

### What Happens Each Night

1. At 02:00 UTC, ops0 starts the discovery scan
2. Parallel region scanning completes in 3–5 minutes
3. Cost enrichment runs concurrently, adding estimated monthly costs to each resource
4. A new session is created and visible in the Discovery Sessions list
5. Session comparison runs automatically and highlights any differences from yesterday's scan
6. If configured, a notification is sent summarizing the comparison: "2 resources modified, 1 added, $12.40/mo cost increase"

---

## Multi-Account and Multi-Provider Scheduling

For environments spanning multiple cloud accounts or providers, create one schedule per integration. Stagger start times to avoid hitting cloud API rate limits simultaneously:

| Schedule | Integration | Cron |
|----------|------------|------|
| `aws-prod-daily` | AWS Production | `0 2 * * *` |
| `aws-staging-daily` | AWS Staging | `0 2:30 * * *` |
| `gcp-prod-daily` | GCP Production | `0 3 * * *` |
| `azure-prod-daily` | Azure Production | `0 3:30 * * *` |

**API Rate Limits**

Cloud providers throttle API calls. If a scheduled scan is scanning many regions and resource types, offset overlapping schedules by at least 30 minutes to stay within limits. AWS defaults allow roughly 10 Describe/List calls per second per service.

---

## Notifications

Configure notifications so your team is alerted when scheduled scans complete or detect drift. Supported channels:

| Channel | Configuration |
|---------|--------------|
| **Email** | Recipients receive a summary with resource counts and cost delta |
| **Slack** | Post to a channel via webhook integration |
| **Webhook** | Send a JSON payload to any HTTP endpoint |

Notification triggers:
- Scan completed (always)
- Drift detected (only when comparison finds changes)
- Scan failed (always on error)

Set up notification channels at **Settings → Integrations → Alerts**.

---

## Best Practices

**Scheduling Tips**

- **Start with daily.** Most teams find daily scans at a low-traffic hour sufficient to catch drift before it causes incidents.
- **Stagger multi-account scans.** Offset by 30–60 minutes to stay within cloud API rate limits.
- **Use resource type filtering.** Scanning only the resource types you manage in IaC reduces scan time and focuses comparison results.
- **Pin baselines after audits.** Save a named baseline after each compliance audit so you can track drift from that known-good state.
- **Test before scheduling.** Run the configuration manually first to verify permissions and confirm the scan completes successfully.

---

## Related

- [Drift Detection](https://docs.ops0.com/docs/discovery/drift-detection): Interpret session comparison results and act on detected drift.

- [Scanning Resources](https://docs.ops0.com/docs/discovery/scanning): Configure scan scope, regions, and resource types.

- [Discovery Overview](https://docs.ops0.com/docs/discovery/overview): How discovery sessions work end to end.
