fix(p3-batch): восстановление 13 Fable 5 P3-fixes из lost branches #1301

Merged
bot-backend merged 13 commits from recover/fable5-p3-batch-2026-06-13 into main 2026-06-13 10:06:06 +00:00
Showing only changes of commit d694e735cd - Show all commits

View file

@ -126,6 +126,11 @@ def _way_to_polygon_wkt(nodes: list[dict]) -> str | None:
Используется для natural=water (озёра, пруды). Если кольцо не замкнуто
автоматически добавляем первую точку в конец.
PostGIS отвергает linear ring < 4 точек. Замкнутый way из 3 точек
[A, B, A] (points[0]==points[-1]) даёт POLYGON((A,B,A)) "geometry
requires more points". Возвращаем None, чтобы caller сделал fallback
на LineString или пропустил элемент.
"""
points = [f"{n['lon']} {n['lat']}" for n in nodes if "lon" in n and "lat" in n]
if len(points) < 3:
@ -133,6 +138,9 @@ def _way_to_polygon_wkt(nodes: list[dict]) -> str | None:
# Замкнуть кольцо если нужно
if points[0] != points[-1]:
points.append(points[0])
# Итоговое кольцо должно содержать ≥4 точек (PostGIS требование).
if len(points) < 4:
return None
return f"POLYGON(({', '.join(points)}))"
@ -203,35 +211,50 @@ def sync_noise_sources_to_db() -> dict[str, int]:
**geom_params,
}
result = db.execute(
text(f"""
INSERT INTO osm_noise_sources_ekb
(osm_type, osm_id, source_type, road_class, name, geom, tags, fetched_at)
VALUES (
:osm_type, :osm_id, :source_type, :road_class, :name,
{geom_sql},
CAST(:tags AS jsonb), NOW()
)
ON CONFLICT (osm_type, osm_id) DO UPDATE
SET source_type = EXCLUDED.source_type,
road_class = EXCLUDED.road_class,
name = EXCLUDED.name,
geom = EXCLUDED.geom,
tags = EXCLUDED.tags,
fetched_at = NOW()
RETURNING (xmax = 0) AS is_insert
"""),
params,
).scalar()
if result:
inserted += 1
else:
updated += 1
try:
with db.begin_nested(): # SAVEPOINT — откат только этой записи
result = db.execute(
text(f"""
INSERT INTO osm_noise_sources_ekb
(osm_type, osm_id, source_type, road_class, name, geom, tags,
fetched_at)
VALUES (
:osm_type, :osm_id, :source_type, :road_class, :name,
{geom_sql},
CAST(:tags AS jsonb), NOW()
)
ON CONFLICT (osm_type, osm_id) DO UPDATE
SET source_type = EXCLUDED.source_type,
road_class = EXCLUDED.road_class,
name = EXCLUDED.name,
geom = EXCLUDED.geom,
tags = EXCLUDED.tags,
fetched_at = NOW()
RETURNING (xmax = 0) AS is_insert
"""),
params,
).scalar()
if result:
inserted += 1
else:
updated += 1
except Exception as e:
# Дефектный way (например, 3-точечное замкнутое кольцо POLYGON((A,B,A))
# отвергается PostGIS) не должен валить весь weekly-sync. SAVEPOINT
# откатывает только эту строку, продолжаем с остальными.
logger.warning(
"noise_sync insert failed for %s/%s (source_type=%s): %s",
osm_type,
osm_id,
source_type,
e,
)
skipped += 1
db.commit()
except Exception:
except Exception as e:
db.rollback()
logger.exception("noise_sync: unexpected error, outer tx rolled back: %s", e)
raise
finally:
db.close()