Files
satellite-provider/_docs/02_document/components/03_tile_downloader/description.md
T
Oleksandr Bezdieniezhnykh b0fffa6d42 [AZ-284] Autodev baseline + testability refactor
Phase A baseline outputs from /autodev (Steps 1-5):
- Problem & solution docs (_docs/00_problem, _docs/01_solution)
- Codebase documentation (_docs/02_document) incl. architecture,
  module-layout, glossary, system-flows, baseline compliance scan
- Test specs (blackbox, performance, resilience, security, resource,
  traceability matrix)
- Test task decomposition (_docs/02_tasks/todo): AZ-285..AZ-290
- Testability refactor (_docs/04_refactoring/01-testability-refactoring):
  - TC-01 Move DownloadedTileInfoV2 + new ExistingTileInfo to Common.DTO
  - TC-02 Replace dead ISatelliteDownloader API with real signatures
  - TC-03 GoogleMapsDownloaderV2 implements ISatelliteDownloader
  - TC-04 TileService depends on ISatelliteDownloader (mockable)
  - TC-05 DI + endpoints use ISatelliteDownloader
- Test runner scripts (scripts/run-tests.sh, run-performance-tests.sh)
- Autodev state pointer (_docs/_autodev_state.md)

Prepares the codebase for AZ-285..AZ-290 unit/integration test work.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 04:44:08 +03:00

3.7 KiB
Raw Blame History

TileDownloader

1. High-Level Overview

Purpose: Acquires satellite imagery tiles from Google Maps, stores them on disk, and persists metadata to the database. Handles session tokens, concurrent downloads, retry logic, and tile deduplication.

Architectural Pattern: Service + Gateway (wraps external API with retry/throttling)

Upstream dependencies: Common (DTOs, GeoUtils, configs), DataAccess (TileEntity, ITileRepository)

Downstream consumers: RegionProcessing (via ITileService), WebApi (GoogleMapsDownloaderV2 directly for single-tile endpoints)

2. Internal Interfaces

Class: GoogleMapsDownloaderV2

Method Input Output Async Error Types
DownloadSingleTileAsync lat, lon, zoomLevel, CancellationToken DownloadedTileInfoV2 Yes ArgumentException, RateLimitException, HttpRequestException
GetTilesWithMetadataAsync center, radiusM, zoom, existingTiles, CancellationToken List<DownloadedTileInfoV2> Yes ArgumentException, RateLimitException, HttpRequestException

Service: TileService (implements ITileService)

Method Input Output Async Error Types
DownloadAndStoreTilesAsync lat, lon, sizeM, zoom, CancellationToken List<TileMetadata> Yes propagated from downloader
GetTileAsync Guid TileMetadata? Yes NpgsqlException
GetTilesByRegionAsync lat, lon, sizeM, zoom IEnumerable<TileMetadata> Yes NpgsqlException

4. Data Access Patterns

Caching Strategy

Data Cache Type TTL Invalidation
Tile bytes In-memory (IMemoryCache, WebApi layer) 1h absolute, 30min sliding None (manual restart)
Tile metadata Database Until year rollover Version-based (current year)
Active downloads ConcurrentDictionary Duration of download Removed on completion

5. Implementation Details

Algorithmic Complexity: Tile grid calculation is O(w×h) where w×h is the number of tiles covering the bounding box.

State Management: _activeDownloads (ConcurrentDictionary) prevents duplicate concurrent downloads. _downloadSemaphore limits parallelism.

Key Dependencies:

Library Version Purpose
Newtonsoft.Json 13.0.4 Serialize session creation request body
IHttpClientFactory built-in Create HttpClient instances per request

Error Handling:

  • Exponential backoff retry for 429 (rate limit) and 5xx errors: 1s → 2s → 4s → 8s → 16s, max 30s, 5 retries
  • Immediate throw for 401/403 (auth errors) and cancellation
  • RateLimitException thrown after exhausting retries on 429

7. Caveats & Edge Cases

  • GoogleMapsDownloaderV2 is registered as a concrete singleton (not behind an interface), creating tight coupling in TileService and Program.cs
  • User-Agent header spoofs Chrome — could be rejected if Google changes detection
  • Allowed zoom levels hardcoded to [15,16,17,18,19] — throws for others
  • Session token rotation threshold (100 tiles) is an educated guess; Google's actual limit is not documented
  • Static _activeDownloads dictionary means deduplication is process-wide, surviving service scope boundaries

8. Dependency Graph

Must be implemented after: Common, DataAccess Can be implemented in parallel with: nothing (needs both foundations) Blocks: RegionProcessing

9. Logging Strategy

Log Level When Example
ERROR Download failure, session token failure Tile download failed. Tile: (X, Y), Status: {StatusCode}
WARN Rate limiting retry Rate limited (429). Waiting {Delay}s before retry
INFO (no INFO-level logs in this component)