Files
satellite-provider/_docs/02_document/components/03_tile_downloader/description.md
T
Oleksandr Bezdieniezhnykh 6b373082c8 [AZ-315] Sync architecture docs after coupling refactor
Phase C of architecture coupling refactor (epic AZ-309). Closes the
last baseline finding (F5 — DataAccess incorrectly documented as
importing Common) and synchronizes the rest of _docs/02_document/
with the post-split project layout from AZ-312/313/314:

- module-layout.md: per-component sections for the three new csprojs
  with explicit ProjectReferences and the no-cross-sibling-reference
  invariant the split enforces.
- architecture.md: components and internal-communication tables
  updated to show calls flow through Common interfaces.
- architecture_compliance_baseline.md: F1..F5 marked Resolved with
  task IDs and commit refs; baseline summary now 0 findings.
- diagrams/components.md, components/03_tile_downloader/description.md,
  modules/{common_interfaces,services_tile_service,
  services_google_maps_downloader,tests_unit}.md updated for the
  split, RateLimitException relocation, and new ITileService methods.

Documentation-only batch — no code, no tests, no build changes.
Epic AZ-309 complete (6 tasks across 3 batches).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 07:25:21 +03:00

4.3 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)

csproj: SatelliteProvider.Services.TileDownloader/SatelliteProvider.Services.TileDownloader.csproj (split out of the monolithic SatelliteProvider.Services project in epic AZ-309)

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

Downstream consumers: RegionProcessing and WebApi — both via ITileService from Common (no compile-time ProjectReference from any consumer to this project's concrete types).

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
GetOrDownloadTileAsync (AZ-310) z, x, y, CancellationToken TileBytes Yes propagated from downloader
DownloadAndStoreSingleTileAsync (AZ-311) lat, lon, zoom, CancellationToken TileMetadata Yes propagated from downloader

4. Data Access Patterns

Caching Strategy

Data Cache Type TTL Invalidation
Tile bytes In-memory (IMemoryCache, owned by TileService since AZ-310) 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 behind ISatelliteDownloader (resolved by AZ-310 cleanup); the previous concrete-type coupling is gone.
  • 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)