Skip to content

RankingsManager

Write-side persistence layer for ranking data, external ID mappings, and symbol discovery within the crawler pipeline.

High-Level Design

Role in the Crawler Pipeline

RankingsManager sits between CrawlingManager (data fetcher) and SymbolAdminManager (human approval):

CrawlingManager                RankingsManager              SymbolAdminManager
(fetch external APIs)  ──►  (persist to symbols table)  ──►  (admin acts on recommendations)
     │                              │
     │  new symbol found            │  insertDiscoveredSymbol()
     │  ─────────────────────────►  │  INSERT OR IGNORE, disabled by default
     │                              │
     │  existing symbol update      │  updateCrawlData()
     │  ─────────────────────────►  │  UPDATE rank + recommendation

RankingsManager never fetches external data itself — it only persists what CrawlingManager provides. This separation keeps the manager stateless and testable.

Three Write Paths

  1. Batch ranking update (updateRankings) — Admin/cron-driven bulk import. Builds dynamic SET clauses per row, skipping unknown symbols and omitting undefined fields. Distinguishes undefined (skip) from null (clear value).

  2. Symbol discovery (insertDiscoveredSymbol) — Crawler inserts newly found symbols. Uses INSERT OR IGNORE for idempotency across repeated crawl runs. Discovered symbols are always non-core (is_core_symbol = 0, enabled_at = NULL). The isEnabled flag is caller-controlled, though in practice CrawlingManager passes false, requiring explicit admin promotion.

  3. Crawl data refresh (updateCrawlData) — Targeted single-symbol update of cmc_rank, coingecko_rank, and recommendation. Called per-symbol on each crawler iteration for already-known symbols.

Static ID Mappings for Core Symbols

getCmcIdMappings() and getCoingeckoIdMappings() return hardcoded constants rather than querying the database. The 26 core symbols have stable, well-known external IDs that don't change — storing them as constants avoids unnecessary DB reads and keeps the mapping reliable even if crawl data is stale.

Direct SQL Access

RankingsManager writes to the symbols table directly via this.durable.state.storage.sql, bypassing SymbolStorageManager. This is a deliberate choice: RankingsManager only touches ranking-related columns (cmc_rank, coingecko_rank, cmc_id, coingecko_id, recommendation), and routing through SymbolStorageManager would add indirection without benefit. The trade-off is that the symbols table schema is a shared concern across both managers.

Edge Cases & Error Handling

  • Unknown symbols in updateRankings() silently skipped — safe for partial bulk imports
  • INSERT OR IGNORE makes insertDiscoveredSymbol() idempotent across repeated crawls
  • Empty updates array returns { updated: 0 } without error
  • SQLite errors during insert caught and returned as error results (not thrown)

See Also