Retry interrupted thematic WCS tiles
This commit is contained in:
@@ -6,6 +6,7 @@ import math
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
from http.client import HTTPException
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable
|
||||
from urllib.error import HTTPError, URLError
|
||||
@@ -55,6 +56,8 @@ class ThematicRasterAcquisitionService:
|
||||
NODATA = -9999.0
|
||||
WCS_TILE_SIDE_M = 10_000.0
|
||||
WCS_REQUEST_INTERVAL_SECONDS = 0.5
|
||||
WCS_FETCH_ATTEMPTS = 3
|
||||
WCS_RETRY_DELAY_SECONDS = 1.0
|
||||
ATTRIBUTION = "Bron: Departement Omgeving, MercatorNet"
|
||||
LICENSE_NOTE = "Publieke GDI-Vlaanderen bron; bronvermelding en productspecifieke gebruiksvoorwaarden blijven van toepassing."
|
||||
|
||||
@@ -305,30 +308,38 @@ class ThematicRasterAcquisitionService:
|
||||
def _fetch(request_url: str, settings: Settings, opener: Callable[..., Any] | None = None) -> tuple[bytes, str]:
|
||||
request = Request(request_url, headers={"Accept": "image/tiff,*/*", "User-Agent": "GeoIntel/0.1 bounded-thematic-raster"})
|
||||
max_bytes = settings.thematic_raster_max_response_mb * 1024 * 1024
|
||||
try:
|
||||
with (opener or urlopen)(request, timeout=settings.thematic_raster_timeout_seconds) as response:
|
||||
content_type = str(response.headers.get("Content-Type", ""))
|
||||
content_length = response.headers.get("Content-Length")
|
||||
if content_length and int(content_length) > max_bytes:
|
||||
raise AppError(code="THEMATIC_RASTER_RESPONSE_TOO_LARGE", message="Official raster response exceeds the configured size limit", status_code=502)
|
||||
content = response.read(max_bytes + 1)
|
||||
except AppError:
|
||||
raise
|
||||
except HTTPError as exc:
|
||||
preview = exc.read(300).decode("utf-8", errors="replace")
|
||||
raise AppError(
|
||||
code="THEMATIC_RASTER_PROVIDER_UNAVAILABLE",
|
||||
message="The official MercatorNet WCS could not complete the bounded request",
|
||||
details={"reason": str(exc), "provider_status_code": int(exc.code), "response_preview": preview},
|
||||
status_code=502,
|
||||
) from exc
|
||||
except (URLError, TimeoutError, OSError) as exc:
|
||||
raise AppError(
|
||||
code="THEMATIC_RASTER_PROVIDER_UNAVAILABLE",
|
||||
message="The official MercatorNet WCS could not complete the bounded request",
|
||||
details={"reason": str(exc)},
|
||||
status_code=502,
|
||||
) from exc
|
||||
for attempt in range(1, ThematicRasterAcquisitionService.WCS_FETCH_ATTEMPTS + 1):
|
||||
try:
|
||||
with (opener or urlopen)(request, timeout=settings.thematic_raster_timeout_seconds) as response:
|
||||
content_type = str(response.headers.get("Content-Type", ""))
|
||||
content_length = response.headers.get("Content-Length")
|
||||
if content_length and int(content_length) > max_bytes:
|
||||
raise AppError(code="THEMATIC_RASTER_RESPONSE_TOO_LARGE", message="Official raster response exceeds the configured size limit", status_code=502)
|
||||
content = response.read(max_bytes + 1)
|
||||
break
|
||||
except AppError:
|
||||
raise
|
||||
except HTTPError as exc:
|
||||
preview = exc.read(300).decode("utf-8", errors="replace")
|
||||
if attempt < ThematicRasterAcquisitionService.WCS_FETCH_ATTEMPTS and int(exc.code) in {429, 500, 502, 503, 504}:
|
||||
time.sleep(ThematicRasterAcquisitionService.WCS_RETRY_DELAY_SECONDS * attempt)
|
||||
continue
|
||||
raise AppError(
|
||||
code="THEMATIC_RASTER_PROVIDER_UNAVAILABLE",
|
||||
message="The official MercatorNet WCS could not complete the bounded request",
|
||||
details={"reason": str(exc), "provider_status_code": int(exc.code), "response_preview": preview, "attempts": attempt},
|
||||
status_code=502,
|
||||
) from exc
|
||||
except (URLError, TimeoutError, OSError, HTTPException) as exc:
|
||||
if attempt < ThematicRasterAcquisitionService.WCS_FETCH_ATTEMPTS:
|
||||
time.sleep(ThematicRasterAcquisitionService.WCS_RETRY_DELAY_SECONDS * attempt)
|
||||
continue
|
||||
raise AppError(
|
||||
code="THEMATIC_RASTER_PROVIDER_UNAVAILABLE",
|
||||
message="The official MercatorNet WCS could not complete the bounded request",
|
||||
details={"reason": str(exc), "attempts": attempt},
|
||||
status_code=502,
|
||||
) from exc
|
||||
if len(content) > max_bytes:
|
||||
raise AppError(code="THEMATIC_RASTER_RESPONSE_TOO_LARGE", message="Official raster response exceeds the configured size limit", status_code=502)
|
||||
if not content.startswith((b"II*\x00", b"MM\x00*")):
|
||||
|
||||
Reference in New Issue
Block a user