feat(sf): включить enable_ird_analyze + latency-hardening (#1115)
Co-authored-by: lekss361 <lekss361@gendsgn.local> Co-committed-by: lekss361 <lekss361@gendsgn.local>
This commit is contained in:
parent
54a501b90a
commit
4cc0b6da8c
8 changed files with 80 additions and 22 deletions
|
|
@ -1379,12 +1379,8 @@ def export_parcel_forecast(
|
|||
if format == "docx":
|
||||
return Response(
|
||||
content=render_report_docx(run.result),
|
||||
media_type=(
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
||||
),
|
||||
headers={
|
||||
"Content-Disposition": f'attachment; filename="{base_name}.docx"'
|
||||
},
|
||||
media_type=("application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
|
||||
headers={"Content-Disposition": f'attachment; filename="{base_name}.docx"'},
|
||||
)
|
||||
|
||||
# pptx — байты (PowerPoint OOXML), отдельной веткой (зеркало docx early-return),
|
||||
|
|
@ -1395,9 +1391,7 @@ def export_parcel_forecast(
|
|||
media_type=(
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
||||
),
|
||||
headers={
|
||||
"Content-Disposition": f'attachment; filename="{base_name}.pptx"'
|
||||
},
|
||||
headers={"Content-Disposition": f'attachment; filename="{base_name}.pptx"'},
|
||||
)
|
||||
|
||||
if format == "json":
|
||||
|
|
@ -3003,7 +2997,11 @@ def analyze_parcel(
|
|||
db, geom_wkt, centroid_lon, centroid_lat
|
||||
)
|
||||
except Exception:
|
||||
logger.warning("ird block failed for cad=%s — analyze response unaffected", cad_num)
|
||||
logger.warning(
|
||||
"ird block failed for cad=%s — analyze response unaffected",
|
||||
cad_num,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
return result_payload
|
||||
|
||||
|
|
|
|||
|
|
@ -135,11 +135,11 @@ class Settings(BaseSettings):
|
|||
openrouteservice_api_key: str = ""
|
||||
|
||||
# ИРД-слой в analyze (#1067 D9b «GG-форсайт»): поле `ird` в ответе analyze —
|
||||
# parcel_ird_overlaps (м.132, incl opportunity) + функц.зона/КРТ (геопортал WFS) +
|
||||
# ПЗЗ-регламент зоны (C8b). Default OFF: источники 2-3 — live-зависимость от внешнего
|
||||
# ЕКБ-геопортала (reverse-eng, без SLA) в hot-пути analyze. Включать после прогона
|
||||
# harvest на проде (B6) и заполнения zone_regulation_cache.
|
||||
enable_ird_analyze: bool = False
|
||||
# parcel_ird_overlaps (м.132, incl opportunity) + КРТ (геопортал WFS) +
|
||||
# ПЗЗ-регламент зоны (C8b). Включён 2026-06-07 после B6-harvest + прогрева
|
||||
# zone_regulation_cache (#1102). Override через env ENABLE_IRD_ANALYZE=false остаётся
|
||||
# возможен. functional_zone выключен — слой пуст в геопортале ЕКБ (0 фич, #1058).
|
||||
enable_ird_analyze: bool = True
|
||||
|
||||
|
||||
settings = Settings()
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ from app.services.site_finder.zone_regulation import get_or_fetch_zone_regulatio
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Короткий timeout для geoportal-вызовов в hot-пути analyze (default клиента — 20s, слишком долго).
|
||||
_GEOPORTAL_TIMEOUT_S = 8
|
||||
_GEOPORTAL_TIMEOUT_S = 4
|
||||
|
||||
|
||||
def _functional_zone_at(
|
||||
|
|
@ -105,10 +105,14 @@ def build_ird_analyze_block(
|
|||
"krt": [],
|
||||
"zone_regulation": None,
|
||||
}
|
||||
# guard активен только в unit-тестах; в prod centroid_lon/lat всегда float
|
||||
# (EKB-fallback в parcels.py).
|
||||
# Geoportal-источники — только при валидном centroid (network, опц.).
|
||||
if lon is not None and lat is not None:
|
||||
client = client or EKBGeoportalClient(timeout=_GEOPORTAL_TIMEOUT_S)
|
||||
block["functional_zone"] = _functional_zone_at(client, lon, lat)
|
||||
# Слой генплан-функц.зон пуст в геопортале ЕКБ (0 фич, 2026-06); источник = ФГИС ТП (#1058).
|
||||
# Не дёргаем geoportal впустую — вернём _functional_zone_at когда появится ingest.
|
||||
block["functional_zone"] = None
|
||||
block["krt"] = _krt_at(client, lon, lat)
|
||||
block["zone_regulation"] = _zone_regulation_at(db, client, lon, lat)
|
||||
return block
|
||||
|
|
|
|||
|
|
@ -141,6 +141,19 @@ _PATCHES = [
|
|||
),
|
||||
patch("app.api.v1.parcels.compute_velocity", return_value=None),
|
||||
patch("app.api.v1.parcels.compute_gate_verdict", return_value={"verdict": "unknown"}),
|
||||
# enable_ird_analyze=True by default — мокаем чтобы не делать сетевые вызовы в тестах
|
||||
patch(
|
||||
"app.api.v1.parcels.build_ird_analyze_block",
|
||||
return_value={
|
||||
"ird_overlaps": [],
|
||||
"ird_by_kind": {},
|
||||
"opportunity_overlaps": [],
|
||||
"planning_projects": [],
|
||||
"functional_zone": None,
|
||||
"krt": [],
|
||||
"zone_regulation": None,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -270,9 +283,9 @@ def test_inline_weights_rejects_nan() -> None:
|
|||
content=raw_body,
|
||||
headers={"Content-Type": "application/json"},
|
||||
)
|
||||
assert resp.status_code == 422, (
|
||||
f"Ожидали 422 для NaN-weight, получили {resp.status_code}: {resp.text}"
|
||||
)
|
||||
assert (
|
||||
resp.status_code == 422
|
||||
), f"Ожидали 422 для NaN-weight, получили {resp.status_code}: {resp.text}"
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
_stop_patches()
|
||||
|
|
|
|||
|
|
@ -140,6 +140,19 @@ _PATCHES = [
|
|||
),
|
||||
patch("app.api.v1.parcels.compute_velocity", return_value=None),
|
||||
patch("app.api.v1.parcels.compute_gate_verdict", return_value={"verdict": "unknown"}),
|
||||
# enable_ird_analyze=True by default — мокаем чтобы не делать сетевые вызовы в тестах
|
||||
patch(
|
||||
"app.api.v1.parcels.build_ird_analyze_block",
|
||||
return_value={
|
||||
"ird_overlaps": [],
|
||||
"ird_by_kind": {},
|
||||
"opportunity_overlaps": [],
|
||||
"planning_projects": [],
|
||||
"functional_zone": None,
|
||||
"krt": [],
|
||||
"zone_regulation": None,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -147,6 +147,19 @@ _PATCHES = [
|
|||
),
|
||||
patch("app.api.v1.parcels.compute_velocity", return_value=None),
|
||||
patch("app.api.v1.parcels.compute_gate_verdict", return_value={"verdict": "unknown"}),
|
||||
# enable_ird_analyze=True by default — мокаем чтобы не делать сетевые вызовы в тестах
|
||||
patch(
|
||||
"app.api.v1.parcels.build_ird_analyze_block",
|
||||
return_value={
|
||||
"ird_overlaps": [],
|
||||
"ird_by_kind": {},
|
||||
"opportunity_overlaps": [],
|
||||
"planning_projects": [],
|
||||
"functional_zone": None,
|
||||
"krt": [],
|
||||
"zone_regulation": None,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -129,6 +129,19 @@ _PATCHES = [
|
|||
),
|
||||
patch("app.api.v1.parcels.compute_velocity", return_value=None),
|
||||
patch("app.api.v1.parcels.compute_gate_verdict", return_value={"verdict": "unknown"}),
|
||||
# enable_ird_analyze=True by default — мокаем чтобы не делать сетевые вызовы в тестах
|
||||
patch(
|
||||
"app.api.v1.parcels.build_ird_analyze_block",
|
||||
return_value={
|
||||
"ird_overlaps": [],
|
||||
"ird_by_kind": {},
|
||||
"opportunity_overlaps": [],
|
||||
"planning_projects": [],
|
||||
"functional_zone": None,
|
||||
"krt": [],
|
||||
"zone_regulation": None,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,9 @@ def _patch_overlay(monkeypatch: Any, overlay: dict[str, Any]) -> None:
|
|||
|
||||
|
||||
def test_full_block_assembly(monkeypatch: Any) -> None:
|
||||
"""Все источники → overlaps + split opportunity + функц.зона + КРТ + регламент."""
|
||||
"""Все источники → overlaps + split opportunity + КРТ + регламент.
|
||||
functional_zone всегда None: слой пуст в геопортале ЕКБ (0 фич, 2026-06) — WFS не дёргается.
|
||||
"""
|
||||
_patch_overlay(monkeypatch, _OVERLAY)
|
||||
monkeypatch.setattr(
|
||||
ird_analyze,
|
||||
|
|
@ -67,7 +69,9 @@ def test_full_block_assembly(monkeypatch: Any) -> None:
|
|||
"opportunity_auction",
|
||||
"opportunity_krt",
|
||||
]
|
||||
assert block["functional_zone"] == {"name": "Ж-зона"}
|
||||
# functional_zone WFS выключен (слой пуст в геопортале ЕКБ, #1058) — всегда None
|
||||
assert block["functional_zone"] is None
|
||||
assert "functional_zone" not in [layer for layer, _, _ in client.calls]
|
||||
assert block["krt"] == [{"num_oks_krt": "КРТ-7"}]
|
||||
assert block["zone_regulation"] == {"zone_index": "Ц-1"}
|
||||
assert block["planning_projects"] == _PLANNING
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue