πΈοΈ dicechess-sync β ΡΠ»ΡΠΆΠ΅Π±Π½Π°Ρ ΡΠΏΡΠ°Π²ΠΊΠ°
dicechess-sync β ΠΏΡΠΈΠ²Π°ΡΠ½ΡΠΉ ΡΠ΅ΡΠ²ΠΈΡ Π±ΡΠΊΡΠΈΠ»Π»Π°: ΠΎΠ½ ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΡ Π³ΡΠ°Ρ ΠΈΠ³ΡΠΎΠΊΠΎΠ² dicechess.com, ΡΠΊΠ°ΡΠΈΠ²Π°Π΅Ρ ΠΈΡΡΠΎΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΠΏΠ°ΡΡΠΈΠΈ, Π½ΠΎΡΠΌΠ°Π»ΠΈΠ·ΡΠ΅Ρ ΠΈΡ
ΠΈ Π·Π°Π»ΠΈΠ²Π°Π΅Ρ Π² Π°Π½Π°Π»ΠΈΡΠΈΠΊΡ, ΠΏΠΎΠΏΡΡΠ½ΠΎ Π·Π΅ΡΠΊΠ°Π»Ρ ΡΡΡΡΡ Π² bronze-Π°ΡΡ
ΠΈΠ².
ΠΡΠ° ΡΡΡΠ°Π½ΠΈΡΠ° β ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΎΠ½Π½Π°Ρ ΡΠΏΡΠ°Π²ΠΊΠ° Β«ΠΊΠ°ΠΊ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ ΠΈ Π½Π°ΡΡΡΠ°ΠΈΠ²Π°ΡΡΒ». ΠΠ°ΠΊ ΠΎΠ½ΠΎ ΡΡΡΡΠΎΠ΅Π½ΠΎ ΠΏΠΎ ΡΡΡΠ΅ΡΡΠ²Ρ β Π² ΡΠΏΠ°ΠΉΠ½Π΅:
- Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ° ΠΈ ΠΌΠ΅ΡΡΠΎ Π² ΡΠΈΡΡΠ΅ΠΌΠ΅ β 03 Π‘ΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ β ΠΎΠ±Π·ΠΎΡ ΠΈ Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ°;
- Π³ΡΠ°Ρ ΠΈΠ³ΡΠΎΠΊΠΎΠ² ΠΈ ΠΏΠ΅ΡΠ΅ΡΠΈΡΠ»Π΅Π½ΠΈΠ΅ β 04 ΠΡΠ°Ρ ΠΈΠ³ΡΠΎΠΊΠΎΠ² ΠΈ ΠΏΠ΅ΡΠ΅ΡΠΈΡΠ»Π΅Π½ΠΈΠ΅;
- ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅Ρ ΠΏΠ°ΡΡΠΈΠΈ ΠΈ ΠΌΠ°ΡΠΈΠ½Ρ ΡΠΎΡΡΠΎΡΠ½ΠΈΠΉ β 05 ΠΠΎΠ½Π²Π΅ΠΉΠ΅Ρ ΠΏΠ°ΡΡΠΈΠΉ ΠΈ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ;
- rate-limiting ΠΈ ΠΎΠ±Ρ ΠΎΠ΄ Cloudflare β 06 ΠΠ°ΡΠΈΡΠ° ΠΎΡ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΎΠΊ ΠΈ Cloudflare;
- ΠΊΠΎΠ½ΡΡΠ°ΠΊΡ ingest ΠΈ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ Π΄Π²ΠΈΠΆΠΊΠΎΠΌ β 07 ΠΠΎΠ½ΡΡΠ°ΠΊΡ ingest ΠΈ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ Π΄Π²ΠΈΠΆΠΊΠΎΠΌ;
- ΠΈΠ΄Π΅Π½ΡΠΈΡΠ½ΠΎΡΡΡ ΠΈ Π΄Π΅Π΄ΡΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡ β 08 ΠΠ΄Π΅Π½ΡΠΈΡΠ½ΠΎΡΡΡ, ΠΈΡΡΠΎΡΠ½ΠΈΠΊΠΈ ΠΈ Π΄Π΅Π΄ΡΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡ.
ΠΠΎΡΠ΅ΠΌΡ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠΉ ΠΏΡΠΈΠ²Π°ΡΠ½ΡΠΉ
ΠΠ½ ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ ΠΎΠ±ΡΠ°ΡΠ½ΡΡ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΡ (reverse engineering) ΠΏΡΠΈΠ²Π°ΡΠ½ΠΎΠ³ΠΎ API dicechess.com β ΠΏΡΠ±Π»ΠΈΡΠ½ΠΎΠ³ΠΎ ΡΠ°Π·ΡΠ΅ΡΠ΅Π½ΠΈΡ Π½Π° Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ ΡΠ±ΠΎΡ Π½Π΅Ρ, ΠΏΠΎΡΡΠΎΠΌΡ Π²ΡΡ ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ° ΡΠΊΡΠ΅ΠΉΠΏΠΈΠ½Π³Π° ΠΈ ΠΎΠ±Ρ ΠΎΠ΄Π° Π·Π°ΡΠΈΡΡ Π²ΡΠ½Π΅ΡΠ΅Π½Π° Π² ΠΏΡΠΈΠ²Π°ΡΠ½ΡΠΉ ΠΊΠΎΠ½ΡΡΡ. ΠΡΠ±Π»ΠΈΡΠ½ΡΠ΅ ΠΏΡΠΎΠ΅ΠΊΡΡ (
dicechess-analytics,dicechess-engine-scala) ΠΎΡΡΠ°ΡΡΡΡ ΡΠΈΡΡΡΠΌΠΈ ΠΎΡ ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠΈ ΡΠ°ΠΉΡΠ° β ΠΈΡ Π³ΡΠ°Π½ΠΈΡΠ° β Π½Π΅ΠΉΡΡΠ°Π»ΡΠ½ΡΠΉ ΠΊΠΎΠ½ΡΡΠ°ΠΊΡPOST /api/games.
1. Π‘ΡΠ΅ΠΊ ΠΈ ΡΡΡΡΠΎΠΉΡΡΠ²ΠΎ
- Node β₯ 26, TypeScript ΠΈΡΠΏΠΎΠ»Π½ΡΠ΅ΡΡΡ Π½Π°ΡΠΈΠ²Π½ΠΎ (type-stripping, Π±Π΅Π· ΡΠ°Π³Π° ΡΠ±ΠΎΡΠΊΠΈ).
type: module. - Π‘ΠΎΡΡΠΎΡΠ½ΠΈΠ΅ β Π»ΠΎΠΊΠ°Π»ΡΠ½Π°Ρ SQLite (
./data/sync.db, Π² Docker/app/data/sync.db), WAL, ΠΌΠΈΠ³ΡΠ°ΡΠΎΡ ΠΏΠΎPRAGMA user_version. Π’Π°Π±Π»ΠΈΡΡ:players(ΡΡΠΎΠ½ΡΠΈΡ, ΡΠΌ. 04 ΠΡΠ°Ρ ΠΈΠ³ΡΠΎΠΊΠΎΠ² ΠΈ ΠΏΠ΅ΡΠ΅ΡΠΈΡΠ»Π΅Π½ΠΈΠ΅),games+raw_game_data(ΠΊΠ°ΡΠ°Π»ΠΎΠ³ + ΡΡΡΠΎΠΉ ΠΊΡΡ, ΡΠΌ. 05 ΠΠΎΠ½Π²Π΅ΠΉΠ΅Ρ ΠΏΠ°ΡΡΠΈΠΉ ΠΈ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ),app_meta. - Π’ΡΠ°Π½ΡΠΏΠΎΡΡ ΠΊ ΡΠ°ΠΉΡΡ β
curl-subprocess (Cloudflare ΡΠΈΠ½Π³Π΅ΡΠΏΡΠΈΠ½ΡΠΈΡ TLS), ΠΊ Π°Π½Π°Π»ΠΈΡΠΈΠΊΠ΅ β ΠΎΠ±ΡΡΠ½ΡΠΉfetch. ΠΠ΄ΠΈΠ½RateLimiterΠ½Π° ΠΏΡΠΎΡΠ΅ΡΡ. Π‘ΠΌ. 06 ΠΠ°ΡΠΈΡΠ° ΠΎΡ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΎΠΊ ΠΈ Cloudflare. - ΠΠ±ΡΠ°Π· β
node:26-trixie-slim(OpenSSL 3.5), ΠΏΡΠΈΠ²Π°ΡΠ½ΡΠΉ ΠΏΠ°ΠΊΠ΅Ρ@rabestro/dicechess-raw-archiveΡΡΠ½Π΅ΡΡΡ ΡΠ΅ΡΠ΅Π· BuildKit-secret.
2. CLI-ΠΊΠΎΠΌΠ°Π½Π΄Ρ
ΠΡΠ΅ Π·Π°ΠΏΡΡΠΊΠ°ΡΡΡΡ Π½Π°ΡΠΈΠ²Π½ΡΠΌ Node Π±Π΅Π· ΡΠ±ΠΎΡΠΊΠΈ. Π’ΡΠ΅Π±ΡΡΡ DICECHESS_JWT Π² ΠΎΠΊΡΡΠΆΠ΅Π½ΠΈΠΈ.
| ΠΠΎΠΌΠ°Π½Π΄Π° | ΠΠ°Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ |
|---|---|
node src/sync-player.ts <userId> [maxFetch] | ΠΡΠΊΡΠΈΠ»Π» ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΈΠ³ΡΠΎΠΊΠ° end-to-end: enumerate β fetch (β€ maxFetch, ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ β) β post. Π Π΅Π·ΡΠΌΠΈΡΡΠ΅ΠΌΠΎ: ΠΏΠΎΠ²ΡΠΎΡΠ½ΡΠΉ Π·Π°ΠΏΡΡΠΊ ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΠΈΠ³ΡΠΎΠΊΠ° Π΄Π΅Π»Π°Π΅Ρ ΠΈΠ½ΠΊΡΠ΅ΠΌΠ΅Π½ΡΠ°Π»ΡΠ½ΡΠΉ ΡΠ²ΠΈΠΏ ΠΎΡ ΠΊΡΡΡΠΎΡΠ° synced_through_ms. |
node src/sync-crawl.ts <maxPlayers> <maxFetch> [seedId,β¦] | ΠΠ΄Π½ΠΎΡΠ°Π·ΠΎΠ²ΡΠΉ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½Π½ΡΠΉ ΠΎΠ±Ρ
ΠΎΠ΄ Π³ΡΠ°ΡΠ°: seed-ΠΈΠ³ΡΠΎΠΊΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡΡΡ ΠΊΠ°ΠΊ manual, Π΄Π°Π»ΡΡΠ΅ ΡΠΏΠ°ΠΉΠ΄Π΅Ρ ΠΏΠΎ ΠΏΡΠΈΠΎΡΠΈΡΠ΅ΡΡ. RESYNC_BEFORE=<ISO> ΠΏΠ΅ΡΠ΅ΠΎΡΠ΅ΡΠ΅Π΄ΠΈΡ ΡΡΡΠ°ΡΠ΅Π²ΡΠΈΡ
ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΡ
. |
node src/crawl-service.ts | ΠΠΎΠ»Π³ΠΎΠΈΠ³ΡΠ°ΡΡΠΈΠΉ Π΄Π΅ΠΌΠΎΠ½ (Docker CMD) β ΠΏΠΎΠ²ΡΠΎΡΡΠ΅Ρ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½Π½ΡΠ΅ ΠΏΡΠΎΡ
ΠΎΠ΄Ρ, ΠΏΠΎΠΊΠ° ΡΡΠΎΠ½ΡΠΈΡ Π½Π΅ ΠΎΠΏΡΡΡΠ΅Π΅Ρ, Π·Π°ΡΠ΅ΠΌ ΠΏΡΠΎΡΡΠ°ΠΈΠ²Π°Π΅Ρ. Π‘ΠΌ. Β§4. |
node src/sync-archive.ts | ΠΠ΄Π½ΠΎΡΠ°Π·ΠΎΠ²ΠΎ Π΄ΠΎΡΠΎΠ»ΠΊΠ½ΡΡΡ Π²ΡΡ ΠΊΡΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ΅ ΡΡΡΡΡ Π² bronze-Π°ΡΡ
ΠΈΠ² Π½Π° dexus. Π’ΡΠ΅Π±ΡΠ΅Ρ ARCHIVE_DB_URL. |
Π‘ΠΈΠ΄ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π³ΡΠ°ΡΠ°
Π‘Π΅ΠΉΡΠ°Ρ ΡΡΠΎΠ½ΡΠΈΡ ΡΠΈΠ΄ΠΈΡΡΠ΅ΡΡΡ Π²ΡΡΡΠ½ΡΡ β
SEED_IDS(ΠΈΠ»ΠΈ Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΎΠΌsync-crawl), ΠΈΠ³ΡΠΎΠΊΠΈ ΠΏΠΎΠΏΠ°Π΄Π°ΡΡ Ρdiscovered_via='manual', Π΄Π°Π»ΡΡΠ΅ Π³ΡΠ°Ρ ΡΠ°ΡΡ ΠΎΠ΄ΠΈΡΡΡ ΡΠΏΠ°ΠΉΠ΄Π΅ΡΠΎΠΌ ΠΏΠΎ ΠΎΠΏΠΏΠΎΠ½Π΅Π½ΡΠ°ΠΌ. ΠΠΈΠ΄Π΅ΡΠ±ΠΎΡΠ΄Ρ (leaderboard/x2_leaderboard) β Π·Π°Π΄ΡΠΌΠ°Π½Π½ΡΠΉ ΠΈΡΡΠΎΡΠ½ΠΈΠΊ seedβΠΎΠ² ΠΈ Π·Π°ΡΠ΅Π·Π΅ΡΠ²ΠΈΡΠΎΠ²Π°Π½Ρ ΠΊΠ°ΠΊ Π·Π½Π°ΡΠ΅Π½ΠΈΡdiscovered_via, Π½ΠΎ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ ΡΠ΅ΡΡ Π»ΠΈΠ΄Π΅ΡΠ±ΠΎΡΠ΄ΠΎΠ² ΠΏΠΎΠΊΠ° Π½Π΅ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½. ΠΠΎΠ΄ΡΠΎΠ±Π½Π΅Π΅ ΠΏΡΠΎ ΠΎΠ±Ρ ΠΎΠ΄ β 04 ΠΡΠ°Ρ ΠΈΠ³ΡΠΎΠΊΠΎΠ² ΠΈ ΠΏΠ΅ΡΠ΅ΡΠΈΡΠ»Π΅Π½ΠΈΠ΅.
3. ΠΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅ ΠΎΠΊΡΡΠΆΠ΅Π½ΠΈΡ
| ΠΠ΅ΡΠ΅ΠΌΠ΅Π½Π½Π°Ρ | ΠΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ | ΠΠ°Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ |
|---|---|---|
DICECHESS_JWT | β (ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΠΎ) | Bearer-JWT ΡΠ°ΠΉΡΠ° (ΠΈΠ· Π±ΡΠ°ΡΠ·Π΅ΡΠ°, ΠΆΠΈΠ²ΡΡ ~ΠΌΠ΅ΡΡΡΡ). |
ANALYTICS_BASE_URL | http://192.168.10.3:8020 | ΠΠ°Π·Π° ingest-Π°Π½Π°Π»ΠΈΡΠΈΠΊΠΈ (aurora). |
ANALYTICS_INGEST_TOKEN | '' | Bearer Π΄Π»Ρ POST /api/games. |
DB_PATH | ./data/sync.db | ΠΡΡΡ ΠΊ SQLite. |
ARCHIVE_DB_URL | '' (ΠΏΡΡΡΠΎ β Π°ΡΡ
ΠΈΠ² ΠΏΡΠΎΠΏΡΡΠΊΠ°Π΅ΡΡΡ) | DSN bronze-Π°ΡΡ ΠΈΠ²Π° (dexus :5433). |
DRY_RUN | false | 1/true β enumerate+fetch+cache, Π±Π΅Π· POST. |
REQUEST_MIN_DELAY_MS | 3000 | ΠΠ°Π·ΠΎΠ²ΡΠΉ ΠΈΠ½ΡΠ΅ΡΠ²Π°Π» ΠΌΠ΅ΠΆΠ΄Ρ Π·Π°ΠΏΡΠΎΡΠ°ΠΌΠΈ ΠΊ ΡΠ°ΠΉΡΡ. (1500 Π±ΡΠ» ΡΠ»ΠΈΡΠΊΠΎΠΌ Π±ΡΡΡΡ β Π»ΠΎΠ²ΠΈΠ» 429.) |
REQUEST_JITTER_MS | 1500 | Π‘Π»ΡΡΠ°ΠΉΠ½Π°Ρ Π΄ΠΎΠ±Π°Π²ΠΊΠ° [0, jitter). |
REQUEST_MAX_RETRIES | 5 | Π Π΅ΡΡΠ°ΠΈ Π·Π°ΠΏΡΠΎΡΠ° ΠΏΡΠΈ throttle (ΠΆΠ΄ΡΡ cooldown, ΠΏΠΎΠ²ΡΠΎΡΡΠ΅Ρ ΡΠΎΡ ΠΆΠ΅ Π²ΡΠ·ΠΎΠ²). |
MAX_REQUESTS_PER_HOUR | β (Π½Π΅ Π·Π°Π΄Π°Π½ΠΎ) | Π§Π°ΡΠΎΠ²ΠΎΠΉ Π±ΡΠ΄ΠΆΠ΅Ρ (ΠΎΠΊΠ½ΠΎ 1 Ρ). ΠΠ΅ Π»ΠΎΠ²ΠΈΡ ΠΌΠΈΠ½ΡΡΠ½ΡΠΉ Π²ΡΠΏΠ»Π΅ΡΠΊ β ΡΡΠΎ Π΄Π΅Π»Π°Π΅Ρ spacing. |
ENUMERATE_PAGE_SIZE | 500 | Π Π°Π·ΠΌΠ΅Ρ ΡΡΡΠ°Π½ΠΈΡΡ player/history. ΠΠ»Π°Π²Π½ΡΠΉ ΡΡΡΠ°Π³ ΠΏΡΠΎΡΠΈΠ² Π»ΠΈΠΌΠΈΡΠ° ΠΏΠ΅ΡΠ΅ΡΠΈΡΠ»Π΅Π½ΠΈΡ (Π΄Π»Ρ ΠΊΠΈΡΠΎΠ² ΠΏΠΎΠ΄Π½ΠΈΠΌΠ°ΡΡ Π΄ΠΎ 1000). |
SEED_IDS | [] | id ΠΈΠ³ΡΠΎΠΊΠΎΠ² Π΄Π»Ρ ΠΏΠΎΡΠ΅Π²Π° ΡΡΠΎΠ½ΡΠΈΡΠ° (Π΄Π΅ΠΌΠΎΠ½), ΡΠ΅ΡΠ΅Π· Π·Π°ΠΏΡΡΡΡ. |
BATCH_PLAYERS | 25 | ΠΠ³ΡΠΎΠΊΠΎΠ² Π½Π° ΠΏΡΠΎΡ ΠΎΠ΄ Π΄Π΅ΠΌΠΎΠ½Π°. |
BATCH_FETCH | 200 | ΠΠ°ΡΡΠΈΠΉ-ΡΠ΅ΡΡΠ΅ΠΉ Π½Π° ΠΏΡΠΎΡ ΠΎΠ΄ Π΄Π΅ΠΌΠΎΠ½Π°. |
INTER_PASS_MS | 0 | ΠΠ°ΡΠ·Π° ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΎΡ ΠΎΠ΄Π°ΠΌΠΈ, ΠΏΠΎΠΊΠ° Π΅ΡΡΡ ΡΠ°Π±ΠΎΡΠ°. |
IDLE_MS | 300000 (5 ΠΌΠΈΠ½) | Π‘ΠΎΠ½, ΠΊΠΎΠ³Π΄Π° ΡΡΠΎΠ½ΡΠΈΡ ΠΎΠΏΡΡΡΠ΅Π». |
RESYNC_AFTER_MS | 0 | >0: ΠΏΠ΅ΡΠ΅ΠΎΡΠ΅ΡΠ΅Π΄ΠΈΡΡ ΠΈΠ³ΡΠΎΠΊΠΎΠ², ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΡ
Π΄Π°Π²Π½Π΅Π΅ ΡΡΠΎΠ³ΠΎ (ΠΈΠ½ΠΊΡΠ΅ΠΌ. ΡΠ΅ΡΡΠ΅Ρ Π΄Π΅ΠΌΠΎΠ½Π°). |
Π£ΡΠΎΠΊΠΈ ΠΈ ΡΠΎΠ½ΠΊΠΎΡΡΠΈ Π»ΠΈΠΌΠΈΡΠΎΠ² (429, Π°ΡΠΈΠΌΠΌΠ΅ΡΡΠΈΡ player/history vs game-move-history, pageSize) β 06 ΠΠ°ΡΠΈΡΠ° ΠΎΡ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΎΠΊ ΠΈ Cloudflare.
4. ΠΠ΅ΠΌΠΎΠ½ crawl-service
ΠΠ΄ΠΈΠ½ ΠΏΡΠΎΡΠ΅ΡΡ, ΠΎΠ΄ΠΈΠ½ RateLimiter (Π³Π»ΠΎΠ±Π°Π»ΡΠ½ΡΠΉ single-flight). ΠΠ° ΡΡΠ°ΡΡΠ΅: resetInProgress (Π²ΠΎΠ·Π²ΡΠ°Ρ ΠΏΠΎΠ΄Π²ΠΈΡΡΠΈΡ
in_progress β pending), ΠΏΠΎΡΠ΅Π² SEED_IDS. Π¦ΠΈΠΊΠ» ΠΏΡΠΎΡ
ΠΎΠ΄Π° while (!stop):
flowchart TD A["crawlFrontier<br/>(β€ BATCH_PLAYERS enumerate,<br/>β€ BATCH_FETCH fetch, Π·Π°ΡΠ΅ΠΌ drain post)"] --> B["Π»ΠΎΠ³: players/games/fetch/post/<br/>frontier/cooldown"] B --> C["archive push (Π΅ΡΠ»ΠΈ ARCHIVE_DB_URL)<br/>ΠΠ ΡΠ°ΡΠ°Π»ΡΠ½ΠΎ β Π½Π΅ ΡΠΎΠ½ΡΠ΅Ρ ΡΠΈΠΊΠ»"] C --> D{"Π±ΡΠ» ΠΏΡΠΎΠ³ΡΠ΅ΡΡ?"} D -->|"Π΄Π°"| E["nap INTER_PASS_MS β ΠΏΡΠΎΡ ΠΎΠ΄ Π·Π°Π½ΠΎΠ²ΠΎ"] D -->|"Π½Π΅Ρ"| F{"RESYNC_AFTER_MS > 0?"} F -->|"Π΄Π°, Π΅ΡΡΡ ΡΡΡΠ°ΡΠ΅Π²ΡΠΈΠ΅"| G["requeueStale β ΠΏΡΠΎΡ ΠΎΠ΄ Π·Π°Π½ΠΎΠ²ΠΎ"] F -->|"Π½Π΅Ρ"| H["idle: nap IDLE_MS"] E --> A G --> A H --> A
SIGTERM/SIGINT ΠΏΡΠ΅ΡΡΠ²Π°ΡΡ ΡΠΎΠ½ ΠΈ ΠΎΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°ΡΡ ΡΠΈΠΊΠ» Π°ΠΊΠΊΡΡΠ°ΡΠ½ΠΎ; Π² finally Π·Π°ΠΊΡΡΠ²Π°ΡΡΡΡ Π°ΡΡ
ΠΈΠ² ΠΈ ΠΠ. ΠΡΡ
ΠΈΠ²-ΠΏΡΡ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΡΠΎΡ
ΠΎΠ΄Π° ΠΈΠ΄Π΅ΠΌΠΏΠΎΡΠ΅Π½ΡΠ΅Π½ ΠΈ ΠΎΠ±ΡΡΠ½ΡΡ Π² try/catch β Π½Π΅Π΄ΠΎΡΡΡΠΏΠ½ΠΎΡΡΡ dexus Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ Π²Π°Π»ΠΈΡ ΠΊΡΠ°ΡΠ»ΠΈΠ½Π³ (ΡΡΡΡΡ ΠΎΡΡΠ°ΡΡΡΡ Π² Π»ΠΎΠΊΠ°Π»ΡΠ½ΠΎΠΌ ΠΊΡΡΠ΅). ΠΠΎΠ»Π½Π°Ρ ΡΡΠ°Π΄ΠΈΡ Π°ΡΡ
ΠΈΠ²Π°ΡΠΈΠΈ β 05 ΠΠΎΠ½Π²Π΅ΠΉΠ΅Ρ ΠΏΠ°ΡΡΠΈΠΉ ΠΈ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ.
5. ΠΠ΅ΠΏΠ»ΠΎΠΉ
- ΠΠ±ΡΠ°Π·
ghcr.io/rabestro/dicechess-sync:latest(+:vX.Y.Z), ΠΌΡΠ»ΡΡΠΈ-Π°ΡΡ (Π² Ρ.Ρ. arm64 ΠΏΠΎΠ΄ Raspberry Pi). docker-compose:restart: unless-stopped, ΡΠΎΠΌsync_data:/app/data(Π΄ΠΎΠ»Π³ΠΎΠ²Π΅ΡΠ½ΠΎΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅),env_file: .env.- ΠΡΡΡΠΈΡΡΡ Π½Π° rpi4 (residential IP β ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»Π΅Π½ Π΄Π»Ρ ΠΏΡΠΎΡ
ΠΎΠΆΠ΄Π΅Π½ΠΈΡ Cloudflare; Ρ Π΄Π°ΡΠ°-ΡΠ΅Π½ΡΡΠΎΠ²ΠΎΠ³ΠΎ/Π½ΠΎΡΡΠ±ΡΡΠ½ΠΎΠ³ΠΎ IP
curlΠ»ΠΎΠ²ΠΈΡ403).
6. Π Π΅Π·ΡΠΌΠΈΡΡΠ΅ΠΌΠΎΡΡΡ ΠΈ ΠΈΠ΄Π΅ΠΌΠΏΠΎΡΠ΅Π½ΡΠ½ΠΎΡΡΡ (ΠΊΡΠ°ΡΠΊΠΎ)
ΠΠ΅ΡΡ ΠΏΡΠΎΠ³ΡΠ΅ΡΡ β Π² SQLite, Π»ΡΠ±ΠΎΠΉ ΡΠ½ΡΡΠΈΠΏΠΎΠΈΠ½Ρ ΠΈ Π΄Π΅ΠΌΠΎΠ½ ΡΠ΅ΡΡΠ°ΡΡΡΡΡΡ ΡΠ²ΠΎΠ±ΠΎΠ΄Π½ΠΎ: resetInProgress ΡΠΈΠ½ΠΈΡ ΠΏΠΎΠ΄Π²ΠΈΡΡΠ΅Π΅, enumerate_offset ΡΠ΅Π·ΡΠΌΠΈΡΡΠ΅Ρ ΠΏΠ΅ΡΠ΅ΡΠΈΡΠ»Π΅Π½ΠΈΠ΅ ΠΊΠΈΡΠ°, synced_through_ms ΠΏΡΠ΅Π²ΡΠ°ΡΠ°Π΅Ρ ΠΏΠΎΠ²ΡΠΎΡΠ½ΡΠΉ Π·Π°ΠΏΡΡΠΊ Π² Π΄Π΅ΡΡΠ²ΡΠΉ ΠΈΠ½ΠΊΡΠ΅ΠΌΠ΅Π½ΡΠ°Π»ΡΠ½ΡΠΉ ΡΠ²ΠΈΠΏ. ΠΠ΄Π΅ΠΌΠΏΠΎΡΠ΅Π½ΡΠ½ΠΎΡΡΡ: ΠΊΠ°ΡΠ°Π»ΠΎΠ³ INSERT OR IGNORE (ΠΏΠ°ΡΡΠΈΡ ΠΈΠ· ΠΈΡΡΠΎΡΠΈΠΉ ΠΎΠ±ΠΎΠΈΡ
ΠΈΠ³ΡΠΎΠΊΠΎΠ² Π·Π°Π²ΠΎΠ΄ΠΈΡΡΡ ΠΎΠ΄ΠΈΠ½ ΡΠ°Π·), ingest 201/200, Π°ΡΡ
ΠΈΠ² first-writer-wins + archived_at. Π Π΅ΠΏΠ»Π΅ΠΉ ΠΈΠ· ΡΡΡΡΡ (replayRejected / replayNormalizeFailures) ΠΏΠ΅ΡΠ΅ΠΊΠΎΠ½Π²Π΅ΡΡΠΈΡΡΠ΅Ρ Π±Π΅Π· ΠΎΠ±ΡΠ°ΡΠ΅Π½ΠΈΡ ΠΊ ΡΠ°ΠΉΡΡ. ΠΠ΅ΡΠ°Π»ΠΈ β 05 ΠΠΎΠ½Π²Π΅ΠΉΠ΅Ρ ΠΏΠ°ΡΡΠΈΠΉ ΠΈ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ.
Π‘Π²ΡΠ·Π°Π½Π½ΠΎΠ΅: 03 Π‘ΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ β ΠΎΠ±Π·ΠΎΡ ΠΈ Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ°, Raw-Π°ΡΡ ΠΈΠ² β bronze-ΡΠ»ΠΎΠΉ, ΠΠΏΠ³ΡΠ΅ΠΉΠ΄ aurora β ΠΏΠ»Π°Π½ ΠΈ ΡΠ΅ΠΊ-Π»ΠΈΡΡ, SSH-ΡΡΠ½Π½Π΅Π»Ρ ΠΊ ΡΠ΅ΡΠ²Π΅ΡΠ½ΠΎΠΌΡ Postgres.