πŸ”„ ETL Pipeline: dicechess-sync

dicechess-sync β€” это ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΉ сСрвис сбора ΠΈ очистки Π΄Π°Π½Π½Ρ‹Ρ… (ETL), ΠΏΡ€Π΅Π΄Π½Π°Π·Π½Π°Ρ‡Π΅Π½Π½Ρ‹ΠΉ для историчСского ΠΈΠΌΠΏΠΎΡ€Ρ‚Π° (backfill) сыгранных ΠΏΠ°Ρ€Ρ‚ΠΈΠΉ с ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ сайта dicechess.com, ΠΈΡ… Π½ΠΎΡ€ΠΌΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΈ синхронизации с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ… dicechess-analytics.

IMPORTANT

ΠŸΡ€ΠΈΡ‡ΠΈΠ½Π° приватности рСпозитория:
Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ содСрТит ΠΎΠ±Ρ€Π°Ρ‚Π½ΡƒΡŽ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ (reverse engineering) ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½ΠΎΠ³ΠΎ API dicechess.com. На сайтС Π½Π΅Ρ‚ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΠ³ΠΎ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ Π½Π° автоматичСский сбор Π΄Π°Π½Π½Ρ‹Ρ…, поэтому всС Π΄Π΅Ρ‚Π°Π»ΠΈ скрСйпинга ΠΈ ΠΎΠ±Ρ…ΠΎΠ΄Π° Π·Π°Ρ‰ΠΈΡ‚Ρ‹ вынСсСны Π² ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ‚ΡƒΡ€. ΠŸΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρ‹ (dicechess-analytics, dicechess-engine-scala) ΠΎΡΡ‚Π°ΡŽΡ‚ΡΡ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ нСзависимыми ΠΈ чистыми ΠΎΡ‚ спСцифики API dicechess.com.


1. АрхитСктурныС Π³Ρ€Π°Π½ΠΈΡ†Ρ‹ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

БСрвис Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΊΠ°ΠΊ мост ΠΌΠ΅ΠΆΠ΄Ρƒ Π·Π°ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΌ Π²Π΅Π±-ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠΌ ΠΈ нашСй ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΠΎΠΉ аналитичСской ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠΎΠΉ.

graph TD
    subgraph dicechess.com [dicechess.com (Π’Π½Π΅ΡˆΠ½ΠΈΠΉ рСсурс)]
        API[Private API]
    end

    subgraph Private_Pipeline [dicechess-sync (ΠŸΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ‚ΡƒΡ€)]
        direction TB
        Crawler[Crawler Daemon / Crawl Service]
        SQLite[(Local SQLite Cache)]
    end

    subgraph Public_Analytics [dicechess-analytics (ΠŸΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ‚ΡƒΡ€)]
        Ingest[POST /api/games Ingest API]
        Postgres[(PostgreSQL Analytical DB)]
        Engine[Scala 3 Engine Validation]
    end

    subgraph Backup_Storage [Dexus Home Server (Архив)]
        DexusArchive[(dicechess-raw-archive)]
    end

    %% ВзаимодСйствия
    API -->|1. Raw JSON (jwt auth)| Crawler
    Crawler <-->|2. Read/Write Catalog & Blobs| SQLite
    Crawler -->|3. GameIngestWire (token auth)| Ingest
    Ingest -->|4. Replay & Validate| Engine
    Ingest -->|5. Write Games & FENs| Postgres
    Crawler -->|6. Mirror Raw Cache| DexusArchive

2. Π›ΠΎΠΊΠ°Π»ΡŒΠ½ΠΎΠ΅ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ Π΄Π°Π½Π½Ρ‹Ρ… (SQLite)

Π›ΠΎΠΊΠ°Π»ΡŒΠ½Π°Ρ Π±Π°Π·Π° Π΄Π°Π½Π½Ρ‹Ρ… SQLite Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΏΠΎ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡƒ Bronze-слоя (Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ сырых Π½Π΅ΠΈΠ·ΠΌΠ΅Π½Π΅Π½Π½Ρ‹Ρ… ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ² API). Π­Ρ‚ΠΎ критичСски Π²Π°ΠΆΠ½ΠΎΠ΅ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π½ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅:

TIP

ΠŸΡ€Π΅ΠΈΠΌΡƒΡ‰Π΅ΡΡ‚Π²ΠΎ сырого кэша:
ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΏΡ€Π°Π²ΠΈΠ»Π° парсинга Ρ…ΠΎΠ΄ΠΎΠ², расчСта FEN ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π½Π° сторонС Π΄Π²ΠΈΠΆΠΊΠ° постоянно Π΄ΠΎΡ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ΡΡ, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΠ°Ρ‚ΡŒ парсСр/Π½ΠΎΡ€ΠΌΠ°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€ Ρ…ΠΎΠ΄ΠΎΠ² ΠΈ ΠΏΠ΅Ρ€Π΅ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ всю ΠΈΡΡ‚ΠΎΡ€ΠΈΡŽ ΠΈΠ³Ρ€ локально, Π½Π΅ дСлая Π½ΠΈ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ запроса ΠΊ Π·Π°Ρ‰ΠΈΡ‰Π΅Π½Π½ΠΎΠΌΡƒ сайту.

Π’Π°Π±Π»ΠΈΡ†Ρ‹ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…:

erDiagram
    players {
        integer user_id PK "DiceChess ID"
        text username
        text player_type "human | bot | guest"
        integer rating_classic
        integer rating_x2
        integer priority "Max known rating"
        text sync_status "pending | in_progress | synced | error"
        integer enumerate_offset "Pagination cursor"
        integer synced_through_ms "StartTime cursor"
    }

    games {
        text game_id PK "UUID"
        text status "discovered | fetched | posted | rejected | error"
        integer white_user_id "FK to players"
        integer black_user_id "FK to players"
        integer started_at_ms "Unix timestamp"
        integer allow_doubling "0/1 (classic/x2)"
        integer is_cancelled
        text post_result "created | exists"
    }

    raw_game_data {
        text game_id PK "FK to games"
        text history_meta_json "Metadata from player history"
        text move_history_json "Verbatim response from game-move-history"
        text move_history_fetched_at
        text archived_at "Timestamp of dexus mirror"
    }

    games ||--o| raw_game_data : "has raw"

3. ΠœΠ°ΡˆΠΈΠ½Ρ‹ состояний (State Machines)

Для Π½Π°Π΄Π΅ΠΆΠ½ΠΎΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ сбоСв сСти, ошибок Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠΈ Π΄Π²ΠΈΠΆΠΊΠ° ΠΈ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΎΠΊ API, процСссы ΠΊΡ€Π°ΡƒΠ»ΠΈΠ½Π³Π° ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΈΠ³Ρ€ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Ρ‹ Π½Π° Π΄Π²Π΅ нСзависимыС ΠΌΠ°ΡˆΠΈΠ½Ρ‹ состояний.

3.1. Π–ΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ» ΠΏΠ°Ρ€Ρ‚ΠΈΠΈ (Games)

stateDiagram-v2
    [*] --> Discovered : Player history enumeration
    Discovered --> Fetched : Fetch game-move-history API
    Discovered --> Error_Fetch : Network / Auth Failure (Retry)
    Error_Fetch --> Discovered : Backoff timer expired
    
    Fetched --> Posted : POST 201 Created / 200 Exists (Ingested)
    Fetched --> Rejected : POST 422 Unprocessable (Invalid Moves)
    Fetched --> Error_Post : 5xx / Ingestion Timeout (Retry)
    Fetched --> Error_Normalize : Parse error / Bug in code
    
    Error_Post --> Fetched : Backoff timer expired
    Error_Normalize --> Fetched : Manual code-fix & DB update
    Rejected --> Fetched : Manual rebuild on Engine upgrade
    
    Posted --> [*]

3.2. Π–ΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ» ΠΊΡ€Π°ΡƒΠ»ΠΈΠ½Π³Π° ΠΈΠ³Ρ€ΠΎΠΊΠ° (Players)

stateDiagram-v2
    [*] --> Pending : Discovered via leaderboard or opponent BFS
    Pending --> In_Progress : Selected by rating priority
    In_Progress --> Synced : All historical pages parsed
    In_Progress --> Error : API blocks / Timeout (Retry)
    Error --> Pending : Backoff timer expired
    Synced --> Pending : Re-queued for incremental updates (START_DATE)

4. ΠšΠΎΠ½Π²Π΅ΠΉΠ΅Ρ€ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π΄Π°Π½Π½Ρ‹Ρ… (The 5-Step Pipeline)

ΠŸΡ€ΠΎΡ†Π΅ΡΡ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΏΠ°Ρ€Ρ‚ΠΈΠΈ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ Π½Π° 5 ΠΈΠ·ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… шагов:

Π¨Π°Π³ 1. Discover (Поиск ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²)

Поиск начинаСтся с «сСмян» (Seeds): Ρ‚ΠΎΠΏ-200 ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² ΠΈΠ· классичСского Π»ΠΈΠ΄Π΅Ρ€Π±ΠΎΡ€Π΄Π° ΠΈ Π»ΠΈΠ΄Π΅Ρ€Π±ΠΎΡ€Π΄Π° X2 (GET /api/leaderboard). ΠžΡ‡Π΅Ρ€Π΅Π΄ΡŒ BFS (ΠΎΠ±Ρ…ΠΎΠ΄ Π² ΡˆΠΈΡ€ΠΈΠ½Ρƒ) растСт Π·Π° счСт добавлСния ΠΎΠΏΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² ΠΈΠ· сыгранных ΠΏΠ°Ρ€Ρ‚ΠΈΠΉ. ΠŸΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚ ΠΎΠ±Ρ…ΠΎΠ΄Π° отдаСтся ΠΈΠ³Ρ€ΠΎΠΊΠ°ΠΌ с ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΌ Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³ΠΎΠΌ.

Π¨Π°Π³ 2. Enumerate (Π‘Π±ΠΎΡ€ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠ°Ρ€Ρ‚ΠΈΠΉ)

Для Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ ΠΈΠ³Ρ€ΠΎΠΊΠ° постранично Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°Π΅Ρ‚ΡΡ Π΅Π³ΠΎ история (POST /api/player/history).

  • Запрос Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠ°Ρ€Ρ‚ΠΈΠΉ (Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³ΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ‚ ΠΈΠ³Ρ€Ρ‹, Π»ΠΈΠΌΠΈΡ‚Ρ‹ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹).
  • НовыС ΠΏΠ°Ρ€Ρ‚ΠΈΠΈ вносятся Π² Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ games Π² статусС discovered.
  • ΠžΠΏΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ Π² Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ players Π² статусС pending (Ссли ΠΈΡ… Ρ‚Π°ΠΌ Π΅Ρ‰Π΅ Π½Π΅ Π±Ρ‹Π»ΠΎ).

Π¨Π°Π³ 3. Fetch Raw (Π‘ΠΊΠ°Ρ‡ΠΈΠ²Π°Π½ΠΈΠ΅ Π»ΠΎΠ³Π° Ρ…ΠΎΠ΄ΠΎΠ²)

Для ΠΏΠ°Ρ€Ρ‚ΠΈΠΉ Π² статусС discovered Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°Π΅Ρ‚ΡΡ Π΄Π΅Ρ‚Π°Π»ΡŒΠ½Ρ‹ΠΉ Π»ΠΎΠ³ состояний доски (GET /api/game-move-history?gameId=...). ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ тяТСлый JSON-ΠΎΡ‚Π²Π΅Ρ‚ сохраняСтся Π±Π΅Π· ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ raw_game_data, пСрСводя ΠΈΠ³Ρ€Ρƒ Π² статус fetched.

Π¨Π°Π³ 4. Normalize (ΠžΡ‡ΠΈΡΡ‚ΠΊΠ° ΠΈ нормализация Ρ…ΠΎΠ΄ΠΎΠ²)

ΠŸΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΉ API game-move-history Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π½Π΅ список Ρ…ΠΎΠ΄ΠΎΠ², Π° Π»ΠΎΠ³ измСнСния состояний (gameMoveHistoryStateMap), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΠΌΠ΅Π΅Ρ‚ ряд особСнностСй:

  • ΠžΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΠΈΠ΅ Ρ‡Π΅Ρ‚ΠΊΠΈΡ… Π³Ρ€Π°Π½ΠΈΡ† Ρ…ΠΎΠ΄ΠΎΠ²: ΠΎΠ΄ΠΈΠ½ Ρ…ΠΎΠ΄ ΠΈΠ³Ρ€ΠΎΠΊΠ° складываСтся ΠΈΠ· Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… записСй β€” события броска ΠΊΡƒΠ±ΠΈΠΊΠΎΠ² ΠΈ ΠΎΡ‚ 1 Π΄ΠΎ 3 событий ΠΌΠΈΠΊΡ€ΠΎ-Ρ…ΠΎΠ΄ΠΎΠ².
  • Π‘ΠΌΠ΅ΡˆΠ°Π½Π½Ρ‹ΠΉ рСгистр Ρ„ΠΈΠ³ΡƒΡ€: Ρ†Π²Π΅Ρ‚ кодируСтся рСгистром Π±ΡƒΠΊΠ² Π² ΠΊΡƒΠ±ΠΈΠΊΠ°Ρ… (P/N/B/R/Q/K β€” Π±Π΅Π»Ρ‹Π΅, p/n/b/r/q/k β€” Ρ‡Π΅Ρ€Π½Ρ‹Π΅).
  • Π‘Π»ΡƒΠΆΠ΅Π±Π½Ρ‹Π΅ записи: состояниС ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ тСхничСскиС ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΊΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ удвоСния ставок ΠΈΠ»ΠΈ сдача ΠΏΠ°Ρ€Ρ‚ΠΈΠΈ).

Нормализатор ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ этот Π»ΠΎΠ³ Π² чистыС Ρ…ΠΎΠ΄Ρ‹: Π±Ρ€ΠΎΡˆΠ΅Π½Π½Ρ‹Π΅ ΠΊΡƒΠ±ΠΈΠΊΠΈ, ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ ΠΌΠΈΠΊΡ€ΠΎ-Ρ…ΠΎΠ΄ΠΎΠ² Π² стандартном Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ ΠΈ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ доски.

Π¨Π°Π³ 5. Post Ingest (ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° Π² Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΡƒ)

Π‘Ρ„ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ JSON-ΠΏΠ°ΠΊΠ΅Ρ‚ (GameIngestWire) отправляСтся Π½Π° endpoint POST /api/games аналитичСского сСрвиса. АналитичСский сСрвис ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ ΠΏΡ€ΠΎΠΊΡ€ΡƒΡ‡ΠΈΠ²Π°Π΅Ρ‚ Ρ…ΠΎΠ΄Ρ‹ Ρ‡Π΅Ρ€Π΅Π· ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ Scala-Π΄Π²ΠΈΠΆΠΎΠΊ, провСряСт ΠΈΡ… Π»Π΅Π³Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ, вычисляСт ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒΠ½Ρ‹Π΅ суммы ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΉ (xxhash64) для Π΄Π΅Π΄ΡƒΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΈ записываСт ΠΏΠ°Ρ€Ρ‚ΠΈΡŽ Π² Π±ΠΎΠ΅Π²ΡƒΡŽ Π‘Π”.


5. Π—Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΎΠΊ (Rate Limiting & Safety)

ΠŸΠΎΡΡ‚ΠΎΡΠ½Π½Ρ‹ΠΉ скрСйпинг историчСского Π°Ρ€Ρ…ΠΈΠ²Π° (сотни тысяч ΠΏΠ°Ρ€Ρ‚ΠΈΠΉ) Π»Π΅Π³ΠΊΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΏΡ€ΠΎΠ²ΠΎΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π±Π°Π½ со стороны хостинга ΠΈΠ»ΠΈ Cloudflare. Π’ dicechess-sync встроСна многоуровнСвая Π·Π°Ρ‰ΠΈΡ‚Π°:

  1. Single-flight Queue: ВсС внСшниС запросы ΠΊ сайту строго ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹. Запросы Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎ с ΠΎΠ΄Π½ΠΎΠ³ΠΎ JWT-Ρ‚ΠΎΠΊΠ΅Π½Π°.
  2. Π‘Π»ΡƒΡ‡Π°ΠΉΠ½Ρ‹ΠΉ Jitter: ΠœΠ΅ΠΆΠ΄Ρƒ запросами выдСрТиваСтся случайная ΠΏΠ°ΡƒΠ·Π° (Π΄ΠΆΠΈΡ‚Ρ‚Π΅Ρ€) ΠΎΡ‚ 1 Π΄ΠΎ 3 сСкунд для ΠΈΠΌΠΈΡ‚Π°Ρ†ΠΈΠΈ чСловСчСского повСдСния.
  3. ΠžΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ Cloudflare Challenge: Если API Π½Π°Ρ‡ΠΈΠ½Π°Π΅Ρ‚ ΠΎΡ‚Π΄Π°Π²Π°Ρ‚ΡŒ страницу с ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΎΠΉ ΠΊΠ°ΠΏΡ‡ΠΈ ΠΈΠ»ΠΈ 403 Forbidden, ΠΊΡ€Π°ΡƒΠ»Π΅Ρ€ Π½Π΅ΠΌΠ΅Π΄Π»Π΅Π½Π½ΠΎ останавливаСтся, отправляя ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅ администратору, вмСсто Ρ‚ΠΎΠ³ΠΎ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠ΅Ρ€Π΅Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π΄ΠΎΠΌΠ΅Π½ запросами.
  4. Exponential Backoff: ΠŸΡ€ΠΈ сСтСвых ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ… ΠΈΠ»ΠΈ 429 Too Many Requests врСмя оТидания Π΄ΠΎ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ запроса увСличиваСтся ΡΠΊΡΠΏΠΎΠ½Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎ (Π΄ΠΎ Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… часов).

6. Π—Π΅Ρ€ΠΊΠ°Π»ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π°Ρ€Ρ…ΠΈΠ²Π° (Archiving)

ΠŸΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎ основному ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅Ρ€Ρƒ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ нСзависимый Ρ„ΠΎΠ½ΠΎΠ²Ρ‹ΠΉ ΠΏΠΎΡ‚ΠΎΠΊ Π°Ρ€Ρ…ΠΈΠ²Π°Ρ†ΠΈΠΈ. Он считываСт сырыС Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ raw_game_data ΠΈ Π·Π΅Ρ€ΠΊΠ°Π»ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΈΡ… Π½Π° Ρ†Π΅Π½Ρ‚Ρ€Π°Π»ΡŒΠ½Ρ‹ΠΉ сСрвСр бэкапов dexus Π² Π±Π°Π·Ρƒ dicechess-raw-archive. Π­Ρ‚ΠΎ обСспСчиваСт 100% ΡΠΎΡ…Ρ€Π°Π½Π½ΠΎΡΡ‚ΡŒ истории ΠΈΠ³Ρ€ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π½Π° случай ΡƒΡ‚Π΅Ρ€ΠΈ локального диска ΠΈΠ»ΠΈ ΠΏΠΎΠ»ΠΎΠΌΠΊΠΈ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°.