# How OpenSEO Handles Scheduled Rank Checks: Cloudflare Workers Cron Architecture Explained

> Discover how OpenSEO uses Cloudflare Workers cron triggers for scheduled rank checks. Learn about its efficient architecture for monitoring keywords and managing runtime budgets.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: architecture
- Published: 2026-08-30

---

**OpenSEO executes scheduled rank checks using Cloudflare Workers' cron triggers that invoke `runScheduledRankChecks`, which identifies due configurations, enforces runtime budgets, validates plan eligibility, and launches `RankCheckWorkflow` instances to perform the actual keyword monitoring.**

OpenSEO is an open-source SEO platform that automates rank tracking through robust scheduled tasks. This article explains how the system handles scheduled rank checks using Cloudflare Workers' cron infrastructure, ensuring reliable, cost-controlled execution across free and paid tiers.

## Cron Architecture and Configuration

OpenSEO leverages **Cloudflare Workers' cron triggers** to execute rank checks on a regular schedule. The cron definitions reside in the worker configuration ([`worker-configuration.d.ts`](https://github.com/every-app/open-seo/blob/main/worker-configuration.d.ts)) and are wired into the Cloudflare deployment via the `crons` field in [`wrangler.toml`](https://github.com/every-app/open-seo/blob/main/wrangler.toml).

When a cron tick fires, Cloudflare automatically invokes the scheduled handler, which imports and executes `runScheduledRankChecks` from [`src/server/features/rank-tracking/services/scheduledRankChecks.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/rank-tracking/services/scheduledRankChecks.ts). This entry point serves as the orchestration layer for all automated rank-tracking operations.

## The Execution Flow: Five-Step Processing Pipeline

The `runScheduledRankChecks` function implements a sophisticated five-step pipeline to ensure fair, efficient, and plan-aware task execution.

### Step 1: Identifying Due Configurations

The scheduler first queries `RankTrackingRepository.getDueConfigsWithOrganization` to discover every rank-check configuration whose `nextCheckAt` timestamp has passed. This database query returns all pending jobs across organizations, prioritized by their scheduled execution time.

### Step 2: Enforcing Runtime Limits and Budgets

To prevent cron overruns and control costs, OpenSEO implements strict resource guards:

- **`TICK_DEADLINE_MS`** – A per-tick wall-clock deadline that stops processing new configs once exceeded
- **`SCHEDULED_TASK_UNIT_BUDGET`** – A cap on task units consumed during a single cron invocation

These limits ensure the worker terminates gracefully within Cloudflare's execution constraints, preventing partial processing of configurations that might exceed runtime limits.

### Step 3: Validating Plan Eligibility

For hosted deployments, the system checks organization entitlements via `customerHasPaidPlan`. Configurations belonging to free-plan organizations are immediately skipped and marked with a **"plan_required"** badge. This validation occurs before any resource-intensive workflow launching, protecting infrastructure from unpaid usage.

### Step 4: Atomic Slot Claiming

To guarantee exactly-once execution semantics, `RankTrackingRepository.claimDueConfig` performs an atomic database update that:

- Advances `nextCheckAt` to the next scheduled interval
- Clears any previous `lastSkipReason` 
- Locks the configuration to the current worker instance

If another worker has already claimed the slot, the scheduler logs the conflict and moves to the next configuration, ensuring fairness across the entire config pool.

### Step 5: Launching the RankCheckWorkflow

Once claimed, `beginRankCheckRun` initiates the **`RankCheckWorkflow`** defined in [`src/server/workflows/RankCheckWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/RankCheckWorkflow.ts). This Cloudflare Workflow receives the config object, project ID, and billing context, then executes the following sequence:

1. **`prepareRankCheckKeywords`** – Loads and prepares keyword lists for processing
2. **Execution strategy selection** – Chooses between `runLiveCheck` (immediate) or `runQueuedCheck` (batched) based on the trigger type
3. **Snapshot recording** – Captures ranking data for historical comparison
4. **Finalization** – Updates the repository with status codes, result counts, and error messages

## Manual Triggers and API Integration

While cron triggers handle automation, OpenSEO also supports manual execution via API routes. Developers can programmatically trigger rank checks using the same infrastructure:

```typescript
// Example: manual trigger of a scheduled rank-check (e.g. from an API route)
import { beginRankCheckRun } from "@/server/features/rank-tracking/services/rankCheckRunGuards";
import { RankTrackingRepository } from "@/server/features/rank-tracking/repositories/RankTrackingRepository";

async function triggerManualRun(configId: string, env: Env) {
  const config = await RankTrackingRepository.getConfigById({ configId, projectId: "" });
  if (!config) throw new Error("Config not found");

  await beginRankCheckRun({
    workflow: env.RANK_CHECK_WORKFLOW,
    config,
    projectId: config.projectId,
    billingCustomer: {
      userId: "system",
      userEmail: "system@openseo.so",
      organizationId: config.organizationId,
      projectId: config.projectId,
    },
    keywordsTotal: await RankTrackingRepository.getKeywordCount(config.id),
    trigger: "manual",
    workflowStartErrorMessage: "Failed to start manual rank check",
  });
}

```

This pattern allows administrative interfaces or webhook endpoints to force immediate rank checks without waiting for the next cron tick.

## Error Handling and Fairness Guarantees

The scheduler implements defensive error handling to maintain system stability. When plan validation fails or workflow initiation errors occur, the system logs the failure **without resetting `nextCheckAt`**. This critical design choice prevents "stuck" configurations from re-triggering immediately on the next cron tick, effectively implementing a circuit breaker pattern for problematic jobs.

If a configuration cannot be claimed due to concurrent access, the scheduler logs the conflict and proceeds to the next item, ensuring that a single slow or stuck workflow cannot block the entire queue.

## Summary

- **OpenSEO scheduled rank checks** run on Cloudflare Workers using native cron triggers defined in [`worker-configuration.d.ts`](https://github.com/every-app/open-seo/blob/main/worker-configuration.d.ts) and [`wrangler.toml`](https://github.com/every-app/open-seo/blob/main/wrangler.toml).
- The `runScheduledRankChecks` function in [`src/server/features/rank-tracking/services/scheduledRankChecks.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/rank-tracking/services/scheduledRankChecks.ts) orchestrates the entire process through a five-step pipeline.
- **Runtime guards** (`TICK_DEADLINE_MS` and `SCHEDULED_TASK_UNIT_BUDGET`) prevent cron overruns and control infrastructure costs.
- **Plan validation** occurs before workflow launch, skipping free-tier configs with a "plan_required" badge to protect resources.
- **Atomic claiming** via `RankTrackingRepository.claimDueConfig` ensures exactly-once execution semantics across distributed workers.
- The **`RankCheckWorkflow`** handles the actual keyword processing, deciding between live and queued execution modes based on trigger context.

## Frequently Asked Questions

### How does OpenSEO prevent the same rank check from running twice simultaneously?

OpenSEO uses `RankTrackingRepository.claimDueConfig` to atomically update the `nextCheckAt` timestamp and lock the configuration to the current worker. If another worker has already claimed the slot, the second attempt detects the conflict and skips to the next configuration, ensuring only one workflow instance processes each config at a time.

### Can I trigger a rank check manually outside the cron schedule?

Yes. The `beginRankCheckRun` function accepts a `trigger: "manual"` parameter, allowing API routes or administrative interfaces to launch `RankCheckWorkflow` instances on demand. This uses the same infrastructure as scheduled checks but bypasses the cron-based discovery and claiming logic.

### What happens if a scheduled rank check fails to start?

If workflow initiation fails due to plan validation errors or infrastructure issues, the scheduler logs the error but **does not** reset the `nextCheckAt` timestamp. This prevents the failed configuration from immediately re-entering the queue on the next cron tick, protecting the system from infinite retry loops on persistent errors.

### Where are the cron intervals defined in the OpenSEO codebase?

Cron schedules are defined in [`worker-configuration.d.ts`](https://github.com/every-app/open-seo/blob/main/worker-configuration.d.ts) as TypeScript type definitions and implemented in the Cloudflare [`wrangler.toml`](https://github.com/every-app/open-seo/blob/main/wrangler.toml) file under the `crons` field. These trigger the `scheduledRankChecks` entry point at the specified intervals, which then delegates to `runScheduledRankChecks` for actual processing.