mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-21 20:21:20 +00:00
23ab05766d
Replaces bare strings with two enums in Common/Enums/:
RegionStatus { Queued, Processing, Completed, Failed }
RoutePointType { Start, End, Action, Intermediate }
Adds a Dapper EnumStringTypeHandler<T> (DataAccess/TypeHandlers/)
that round-trips enums to/from lowercase strings, registered once
at startup via DapperEnumTypeHandlers.RegisterAll(). DataAccess now
references Common (project ref) so entities can carry the enum types.
Sites converted: RegionService (5), RouteProcessingService (3),
RoutePointGraphBuilder (4), entity Status/PointType columns. Log
message and summary file format preserved via .ToLowerInvariant().
API JSON contract preserved by adding JsonStringEnumConverter with
JsonNamingPolicy.CamelCase to the http JSON options — single-word
enum members serialize to the same lowercase strings as before.
DTO renamed: Common.DTO.RegionStatus -> RegionStatusResponse to
free the RegionStatus name for the new enum (forced by the task's
explicit enum name); the renamed DTO has no public-API impact at
the JSON wire level. Stale doc references updated.
AC RT2 in _docs/00_problem/acceptance_criteria.md now lists all 4
point types (start/end/action/intermediate).
Tests: 171 / 171 unit + 5 / 5 smoke green (was 141 + 5; +30 new tests
covering type handler round-trip, set/parse, unknown-value rejection,
idempotent registration, and the AC RT2 doc check).
Co-authored-by: Cursor <cursoragent@cursor.com>
92 lines
3.8 KiB
Markdown
92 lines
3.8 KiB
Markdown
# Module: Services/RegionService + RegionProcessingService + RegionRequestQueue
|
||
|
||
## Purpose
|
||
End-to-end region processing pipeline: API request handling → queue → background worker → tile download → output file generation. Three closely coupled classes form the region processing subsystem.
|
||
|
||
## Public Interface
|
||
|
||
### RegionService (implements IRegionService)
|
||
- `RequestRegionAsync(...)`: creates `RegionEntity` with status `RegionStatus.Queued`, enqueues a `RegionRequest`, returns `RegionStatusResponse`
|
||
- `GetRegionStatusAsync(Guid id)`: reads region record and maps to `RegionStatusResponse`
|
||
- `ProcessRegionAsync(Guid id, CancellationToken)`: the main processing pipeline — see Internal Logic
|
||
|
||
### RegionProcessingService (BackgroundService)
|
||
- `ExecuteAsync(CancellationToken)`: spawns `MaxConcurrentRegions` parallel worker tasks, each in an infinite dequeue loop
|
||
|
||
### RegionRequestQueue (implements IRegionRequestQueue)
|
||
- `EnqueueAsync(RegionRequest, CancellationToken)`: writes to a bounded `Channel<RegionRequest>`
|
||
- `DequeueAsync(CancellationToken)`: reads from the channel (blocks until available)
|
||
- `Count`: current queue depth
|
||
|
||
## Internal Logic
|
||
|
||
### RegionService.ProcessRegionAsync
|
||
1. Sets region status to "processing"
|
||
2. Creates a 5-minute timeout `CancellationTokenSource`
|
||
3. Queries existing tiles in the region
|
||
4. Calls `TileService.DownloadAndStoreTilesAsync` to fetch missing tiles
|
||
5. Counts downloaded vs reused tiles
|
||
6. Generates CSV file (`region_{id}_ready.csv`) listing tile coordinates + paths
|
||
7. Optionally stitches tiles into a single JPEG image (if `StitchTiles` is true)
|
||
8. Generates summary file (`region_{id}_summary.txt`)
|
||
9. Updates region status to "completed"
|
||
10. On any error: sets status to "failed", generates error summary
|
||
|
||
### Tile Stitching
|
||
Uses ImageSharp to:
|
||
1. Compute a tile grid from tile coordinates
|
||
2. Create a new image of `(gridWidth × 256) × (gridHeight × 256)` pixels
|
||
3. Place each tile image at its grid position
|
||
4. Draw a red crosshair at the center coordinates
|
||
5. Save as JPEG
|
||
|
||
### Error Handling
|
||
Comprehensive catch blocks for:
|
||
- `TaskCanceledException` (timeout vs external cancellation)
|
||
- `OperationCanceledException`
|
||
- `RateLimitException` (Google rate limiting)
|
||
- `HttpRequestException` (with status code)
|
||
- Generic `Exception`
|
||
Each sets status to "failed" and writes an error summary file.
|
||
|
||
### RegionProcessingService
|
||
- Spawns `MaxConcurrentRegions` worker tasks with staggered startup (100–500ms random delay)
|
||
- Each worker loops: dequeue → `ProcessRegionAsync` → repeat
|
||
- Graceful shutdown on cancellation
|
||
|
||
### RegionRequestQueue
|
||
- Uses `System.Threading.Channels.Channel<T>.CreateBounded` with `BoundedChannelFullMode.Wait`
|
||
- Tracks `_totalEnqueued` and `_totalDequeued` counters
|
||
|
||
## Dependencies
|
||
- `ITileService`, `IRegionRepository`, `IRegionRequestQueue`
|
||
- `StorageConfig`, `ProcessingConfig`
|
||
- `SixLabors.ImageSharp` — tile stitching
|
||
- `SatelliteProvider.Common.Utils.GeoUtils` — coordinate conversion for stitching
|
||
|
||
## Consumers
|
||
- `Program.cs` API endpoints — `RequestRegionAsync`, `GetRegionStatusAsync`
|
||
- `RouteService` — `RequestRegionAsync` (for geofence regions)
|
||
- `RouteProcessingService` — `RequestRegionAsync` (for route-point regions)
|
||
|
||
## Data Models
|
||
- Input: `RegionRequest` (queue message)
|
||
- Output: `RegionStatusResponse` (API response), CSV files, summary files, stitched images
|
||
- Persistence: `RegionEntity`
|
||
|
||
## Configuration
|
||
- `StorageConfig.ReadyDirectory` — output file location
|
||
- `ProcessingConfig.MaxConcurrentRegions` — worker count
|
||
- `ProcessingConfig.QueueCapacity` — bounded channel size
|
||
|
||
## External Integrations
|
||
- PostgreSQL (via repositories)
|
||
- File system (CSV, summary, stitched images in `./ready/`)
|
||
- Google Maps (indirectly via TileService → GoogleMapsDownloaderV2)
|
||
|
||
## Security
|
||
None.
|
||
|
||
## Tests
|
||
Integration tests in `RegionTests.cs` cover the request → poll → complete flow.
|