When do the background workers run?
RankEngine has 3 detection workers that run daily on a leader-locked schedule (only one Cloud Run instance fires them). They populate caches that the Dashboard pending pills row + weekly digest read.
The schedule
| UTC hour | Worker | What it does | Cache table |
|---|---|---|---|
| 06:00 | AI Crawler Probe | Fetches /robots.txt for every installed shop; parses per-bot rules for 15 AI bots; HEAD-checks declared Sitemap: URLs |
ai_crawler_matrix_cache |
| 08:00 | Sitemap Freshness Probe | Fetches /sitemap.xml, expands sitemap-index, aggregates <lastmod> across the tree |
sitemap_freshness_cache |
| 10:00 | Competitor Schema Snapshot | Fetches each tracked competitor's homepage + merchant's own storefront; extracts <script type="application/ld+json"> types; writes to history table |
schema_snapshots |
All three are deliberately spaced 2 hours apart so outbound fetch volume doesn't bunch up.
Why daily?
- Robots.txt + sitemap.xml don't change minute-to-minute. A nightly probe is enough to catch the regression within 24h.
- Schema snapshots are needed for the 7-day diff window — daily granularity is the right resolution.
- Outbound fetch budget: 200 shops × 3 probes × 1-10 sub-fetches each = bounded.
Where the cached data shows up
Phases 780-781 wired cache-on-mount across the audit panels:
- AI Crawler Matrix panel reads
ai_crawler_matrix_cacheon mount (instant render, no robots.txt fetch). Falls back to live probe on cache miss (first-install before the 06:00 UTC worker fires). - Sitemap URL Audit panel shows cached newest-
<lastmod>banner above the audit input (before the merchant clicks Audit). - Dashboard pending pills row also reads all 3 caches in parallel via
/dashboard/pending.
This means the merchant sees the data from the most recent nightly probe within milliseconds of opening a panel, without waiting for a fresh outbound fetch.
What if I want a fresh probe NOW?
- AI crawler matrix — visit SEO Tools → Audit → AI Crawler Access Matrix and click "Re-probe". Fires the live endpoint which UPSERTs the cache AND adds the (live-only) sitemap declarations + wildcard policy fields.
- Sitemap freshness — visit SEO Tools → Audit → Sitemap URL Audit and click "Audit sitemap". Same pattern.
- Competitor schemas — visit SEO Tools → Spy & Compare → Competitor Schema Spy, paste a URL, click "Spy" + "Save snapshot for diff". The URL gets added to the next snapshot cycle.
Retention
| Cache | Retention | Configurable via |
|---|---|---|
ai_crawler_matrix_cache |
rolling (UPSERT only — no history) | — |
sitemap_freshness_cache |
rolling (UPSERT only — no history) | — |
schema_snapshots |
90 days | SCHEMA_SNAPSHOT_RETENTION_DAYS env |
schema_apply_log |
365 days | SCHEMA_APPLY_LOG_RETENTION_DAYS env |
ai_visibility_snapshots |
365 days | AI_VISIBILITY_SNAPSHOT_RETENTION_DAYS env |
competitor_rank_history |
180 days | COMPETITOR_RANK_RETENTION_DAYS env |
keyword_rank_history |
180 days | KEYWORD_RANK_RETENTION_DAYS env |
webhook_event_dedupe |
per-row expires_at |
— (hardcoded TTL on write) |
blog_jobs |
90 days | BLOG_JOBS_RETENTION_DAYS env |
article_performance_history |
365 days | ARTICLE_PERFORMANCE_RETENTION_DAYS env |
seo_optimization_plans |
180 days | SEO_OPTIMIZATION_RETENTION_DAYS env |
seo_optimization_snapshots |
180 days | SEO_OPTIMIZATION_RETENTION_DAYS env |
seo_optimization_batches |
180 days | SEO_OPTIMIZATION_RETENTION_DAYS env |
| search data cache | per-row expires_at |
— (hardcoded TTL on write) |
activity_log |
180 days | ACTIVITY_LOG_RETENTION_DAYS env |
autopilot_activity |
180 days | ACTIVITY_LOG_RETENTION_DAYS env |
sync_log |
90 days | SYNC_LOG_RETENTION_DAYS env |
Note: api_cost_log is intentionally NOT pruned (billing audit / compliance retention).
Retention pruning happens at the end of each schema snapshot worker cycle (10:00 UTC).
How to verify a worker ran
Cloud Run logs (Cloud Console → Logs Explorer) show per-cycle stamps:
[AiCrawlerProbe] Probing N shop(s)at 06:00 UTC[SitemapFreshness] Probing N shop(s)at 08:00 UTC[CompetitorSchemaMonitor] Snapshotting for N shop(s)at 10:00 UTC
Why "leader-locked"?
Cloud Run can scale to multiple instances. Without a lock, all instances would fire the same worker every hour, multiplying outbound fetches. Phase 638+ uses pg_try_advisory_lock(42) so only one instance becomes the "leader" and runs the workers. Other instances skip.
If the leader instance crashes, the lock auto-releases and the next cycle on another instance picks up the leadership.
Related
- AI Crawler Access Matrix — what the 06:00 worker populates
- Sitemap URL Audit — what the 08:00 worker populates
- Schema coverage — you vs competitors — what the 10:00 worker enables