Appearance
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 + recommendationRankingsManager never fetches external data itself — it only persists what CrawlingManager provides. This separation keeps the manager stateless and testable.
Three Write Paths
Batch ranking update (
updateRankings) — Admin/cron-driven bulk import. Builds dynamicSETclauses per row, skipping unknown symbols and omittingundefinedfields. Distinguishesundefined(skip) fromnull(clear value).Symbol discovery (
insertDiscoveredSymbol) — Crawler inserts newly found symbols. UsesINSERT OR IGNOREfor idempotency across repeated crawl runs. Discovered symbols are always non-core (is_core_symbol = 0,enabled_at = NULL). TheisEnabledflag is caller-controlled, though in practice CrawlingManager passesfalse, requiring explicit admin promotion.Crawl data refresh (
updateCrawlData) — Targeted single-symbol update ofcmc_rank,coingecko_rank, andrecommendation. 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 IGNOREmakesinsertDiscoveredSymbol()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
- CrawlingManager — provides the data that this manager persists
- SymbolStorageManager — owns the
symbolstable schema - SymbolAdminManager — acts on recommendations set by this manager
- Parent DO:
SymbolRegistry