# What Background Tasks Are Scheduled in OpenSEO: Cloudflare Workers Cron Guide

> Discover scheduled background tasks in OpenSEO using Cloudflare Workers cron triggers for rank checks, audit reconciliation, referral sweeps, and validation. Learn more now.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-09-09

---

**OpenSEO runs background tasks using Cloudflare Workers' scheduled events (cron triggers) to execute rank-check workflows, audit reconciliation watchdogs, Dub referral sale sweeps, and self-host pre-flight validation.**

The open-source SEO platform OpenSEO (every-app/open-seo) relies on a sophisticated cron-driven architecture to automate monitoring, billing, and data reconciliation. These background tasks execute automatically on defined schedules, handling everything from 5-minute rank tracking updates to daily billing synchronizations. Understanding what background tasks are scheduled in OpenSEO is essential for operators monitoring system health and developers extending the platform.

## How OpenSEO Dispatches Scheduled Tasks

OpenSEO centralizes its cron logic in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) through the Cloudflare Workers `scheduled` export. The handler receives a `ScheduledController` (typed as `ExportedHandlerScheduledHandler`) that contains the triggering cron expression. Based on the cron name, the dispatcher invokes specific workflow bindings configured in the worker environment, such as `RANK_CHECK_WORKFLOW` or `SITE_AUDIT_WORKFLOW`.

```typescript
export const scheduled: ExportedHandlerScheduledHandler = async (controller, env, ctx) => {
  if (controller.cron === "0 */5 * * * *") {
    // Every 5 minutes – rank-check workflow
    await env.RANK_CHECK_WORKFLOW.run({ /* payload */ }, ctx);
  }
  // …other cron names for audit, Dub, etc.
};

```

This architecture ensures that all background tasks share a single entry point while maintaining isolation between different job types.

## Core Background Tasks in OpenSEO

### Rank-Check Workflow

The **rank-check workflow** polls user-defined rank-tracking configurations every five minutes. Defined in [`src/server/workflows/RankCheckWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/RankCheckWorkflow.ts), this task claims work slots, validates plan limits against the database, and triggers individual rank checks for each active configuration. The service implementation 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) contains the core iteration logic. When errors occur, the system logs them with a `[cron]` prefix for easy filtering in Cloudflare Logs.

### Audit Reconciliation Watchdog

Running on each cron tick, the **audit reconciliation watchdog** identifies and resolves stale or timed-out audits. The reconciliation logic lives in [`src/server/features/audit/services/auditReconciler.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/audit/services/auditReconciler.ts), which marks unfinished audits as failed or retries them based on configuration. This watchdog is invoked from the global scheduler in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts), ensuring that audit states remain consistent even when individual jobs fail mid-execution.

### Dub Referral Sale Sweep

A **daily cron job** walks through every referred organization to verify that invoice events from the Dub billing webhook have been processed. Implemented in [`src/server/referrals/dub.ts`](https://github.com/every-app/open-seo/blob/main/src/server/referrals/dub.ts) (marked with a `daily cron` comment), this sweep ensures referral commissions are accurately calculated. Failed sweeps are logged with the specific error message `"[cron] Dub referral sale sweep failed"` and automatically retried on the next tick.

### Self-Host Pre-Flight Checks

Though not triggered by a cron schedule, **self-host pre-flight checks** run as a background task on every worker start. Located in [`src/lib/selfhost-preflight.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/selfhost-preflight.ts), this routine validates that required bindings—KV, R2, D1, and other Cloudflare resources—are properly configured. If validation fails, the worker aborts before processing any requests, preventing runtime errors in mis-configured environments.

### Secondary Stale-Audit Reconcile

As a safety mechanism, a specific `scheduled` handler at the end of [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) performs a secondary pass to catch any unreconciled audit states after the main cron loop completes. This task logs errors with the message `"[cron] Stale-audit reconcile failed"`, providing a final safety net for audit consistency.

## Running and Debugging Background Tasks

You can manually trigger the rank-check workflow for testing purposes by calling the workflow binding directly:

```typescript
import { env } from "./server"; // assume env is populated
await env.RANK_CHECK_WORKFLOW.run(
  { payload: { /* config ID, domain, etc. */ } },
  { waitUntil: (p) => p }   // minimal ExecutionContext stub
);

```

When implementing custom scheduled tasks, follow the established logging convention to ensure errors are traceable:

```typescript
console.error("[cron] Failed to start scheduled rank check for config", config.id);

```

Additionally, auxiliary maintenance scripts for D1 default-project cleanup and cost-profile calculations exist in the `scripts/` directory, though these are invoked manually rather than through the hourly cron loop.

## Summary

- **Rank-Check Workflow**: Runs every 5 minutes via `RANK_CHECK_WORKFLOW` to poll rank-tracking configurations and trigger checks.
- **Audit Reconciliation Watchdog**: Reconciles stale audits on each tick using [`src/server/features/audit/services/auditReconciler.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/audit/services/auditReconciler.ts).
- **Dub Referral Sale Sweep**: Daily cron job in [`src/server/referrals/dub.ts`](https://github.com/every-app/open-seo/blob/main/src/server/referrals/dub.ts) that processes billing webhook events for referrals.
- **Self-Host Pre-Flight Validation**: Startup checks in [`src/lib/selfhost-preflight.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/selfhost-preflight.ts) that validate Cloudflare bindings before accepting traffic.
- **Secondary Stale-Audit Check**: Final safety net in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) that catches unreconciled audit states.

## Frequently Asked Questions

### How often do OpenSEO background tasks run?

The rank-check workflow runs every 5 minutes using the cron pattern `0 */5 * * * *`. The Dub referral sale sweep runs daily, while the audit reconciliation watchdog and secondary stale-audit check execute on every cron tick. Self-host pre-flight checks run once per worker instance start-up.

### Where is the main scheduler entry point in OpenSEO?

The main entry point is the `scheduled` export in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts). This `ExportedHandlerScheduledHandler` receives the `ScheduledController` and routes execution to the appropriate workflow based on the triggering cron expression.

### Can I manually trigger OpenSEO background tasks for testing?

Yes. You can manually invoke workflows such as `RANK_CHECK_WORKFLOW` or `SITE_AUDIT_WORKFLOW` by calling the `.run()` method on the workflow binding, passing a payload and a minimal `ExecutionContext` stub with a `waitUntil` function.

### What happens when a scheduled task fails in OpenSEO?

Failed tasks are logged with a `[cron]` prefix for visibility in Cloudflare Logs. The Dub referral sweep and similar tasks automatically retry on the next cron tick. Rank-check and audit workflows handle failures internally through their respective service layers, updating job statuses without crashing the global scheduler.