Filter runway history by observation time
This commit is contained in:
@@ -4257,8 +4257,11 @@ class DBManager:
|
|||||||
wind_dir, wind_speed, rvr, mor, humidity,
|
wind_dir, wind_speed, rvr, mor, humidity,
|
||||||
otime_utc, created_at
|
otime_utc, created_at
|
||||||
FROM runway_obs_log
|
FROM runway_obs_log
|
||||||
WHERE icao = ? AND created_at >= datetime('now', ? || ' minutes')
|
WHERE icao = ?
|
||||||
ORDER BY created_at ASC
|
AND datetime(COALESCE(NULLIF(otime_utc, ''), created_at))
|
||||||
|
>= datetime('now', ? || ' minutes')
|
||||||
|
ORDER BY datetime(COALESCE(NULLIF(otime_utc, ''), created_at)) ASC,
|
||||||
|
created_at ASC
|
||||||
""",
|
""",
|
||||||
(str(icao).strip().upper(), str(-int(minutes))),
|
(str(icao).strip().upper(), str(-int(minutes))),
|
||||||
).fetchall()
|
).fetchall()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from concurrent.futures import ThreadPoolExecutor, TimeoutError
|
from concurrent.futures import ThreadPoolExecutor, TimeoutError
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@@ -270,11 +271,12 @@ def test_observation_collector_persists_amsc_runway_history(tmp_path):
|
|||||||
observation_store=db,
|
observation_store=db,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
observed_at = datetime.now(timezone.utc).replace(microsecond=0).isoformat()
|
||||||
record = ObservationRecord(
|
record = ObservationRecord(
|
||||||
source="amsc_awos",
|
source="amsc_awos",
|
||||||
city="chengdu",
|
city="chengdu",
|
||||||
value=28.4,
|
value=28.4,
|
||||||
observed_at="2026-06-15T10:51:00+00:00",
|
observed_at=observed_at,
|
||||||
observed_at_local="2026-06-15 18:51:00",
|
observed_at_local="2026-06-15 18:51:00",
|
||||||
station_code="ZUUU",
|
station_code="ZUUU",
|
||||||
station_name="Chengdu Shuangliu",
|
station_name="Chengdu Shuangliu",
|
||||||
@@ -313,11 +315,40 @@ def test_observation_collector_persists_amsc_runway_history(tmp_path):
|
|||||||
rows = db.get_runway_obs_recent("ZUUU", minutes=60)
|
rows = db.get_runway_obs_recent("ZUUU", minutes=60)
|
||||||
|
|
||||||
assert [row["runway"] for row in rows] == ["02L/20R", "02R/20L"]
|
assert [row["runway"] for row in rows] == ["02L/20R", "02R/20L"]
|
||||||
assert rows[0]["otime_utc"] == "2026-06-15T10:51:00+00:00"
|
assert rows[0]["otime_utc"] == observed_at
|
||||||
assert rows[0]["target_runway_max"] == 28.4
|
assert rows[0]["target_runway_max"] == 28.4
|
||||||
assert rows[0]["wind_dir"] == 130
|
assert rows[0]["wind_dir"] == 130
|
||||||
|
|
||||||
|
|
||||||
|
def test_runway_obs_recent_filters_by_observation_time_not_insert_time(tmp_path):
|
||||||
|
from src.database.db_manager import DBManager
|
||||||
|
|
||||||
|
db = DBManager(str(tmp_path / "polyweather.db"))
|
||||||
|
now = datetime.now(timezone.utc).replace(microsecond=0)
|
||||||
|
stale_observed_at = (now - timedelta(hours=3)).isoformat()
|
||||||
|
fresh_observed_at = now.isoformat()
|
||||||
|
|
||||||
|
db.append_runway_obs(
|
||||||
|
icao="ZUUU",
|
||||||
|
city="chengdu",
|
||||||
|
runway="02L/20R",
|
||||||
|
target_runway_max=24.0,
|
||||||
|
otime_utc=stale_observed_at,
|
||||||
|
)
|
||||||
|
db.append_runway_obs(
|
||||||
|
icao="ZUUU",
|
||||||
|
city="chengdu",
|
||||||
|
runway="02R/20L",
|
||||||
|
target_runway_max=25.0,
|
||||||
|
otime_utc=fresh_observed_at,
|
||||||
|
)
|
||||||
|
|
||||||
|
rows = db.get_runway_obs_recent("ZUUU", minutes=60)
|
||||||
|
|
||||||
|
assert [row["runway"] for row in rows] == ["02R/20L"]
|
||||||
|
assert rows[0]["otime_utc"] == fresh_observed_at
|
||||||
|
|
||||||
|
|
||||||
def test_raw_observation_failure_preserves_last_success_and_increments_errors(tmp_path):
|
def test_raw_observation_failure_preserves_last_success_and_increments_errors(tmp_path):
|
||||||
from src.database.db_manager import DBManager
|
from src.database.db_manager import DBManager
|
||||||
|
|
||||||
|
|||||||
@@ -1128,7 +1128,7 @@ def test_chart_scope_overlays_collector_runway_history_from_db(monkeypatch):
|
|||||||
|
|
||||||
def get_runway_obs_recent(self, icao, minutes=60):
|
def get_runway_obs_recent(self, icao, minutes=60):
|
||||||
assert icao == "ZSPD"
|
assert icao == "ZSPD"
|
||||||
assert minutes == 36 * 60
|
assert minutes == 24 * 60
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"runway": "35R/17L",
|
"runway": "35R/17L",
|
||||||
@@ -1163,7 +1163,7 @@ def test_chart_data_force_refresh_overlays_collector_runway_history(monkeypatch)
|
|||||||
class FakeCache:
|
class FakeCache:
|
||||||
def get_runway_obs_recent(self, icao, minutes=60):
|
def get_runway_obs_recent(self, icao, minutes=60):
|
||||||
assert icao == "ZUUU"
|
assert icao == "ZUUU"
|
||||||
assert minutes == 36 * 60
|
assert minutes == 24 * 60
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"runway": "02L/20R",
|
"runway": "02L/20R",
|
||||||
|
|||||||
@@ -1761,7 +1761,7 @@ def _analyze(
|
|||||||
if isinstance(icao, str) and icao:
|
if isinstance(icao, str) and icao:
|
||||||
try:
|
try:
|
||||||
from src.database.db_manager import DBManager
|
from src.database.db_manager import DBManager
|
||||||
raw_runway_obs = DBManager().get_runway_obs_recent(icao, minutes=36 * 60)
|
raw_runway_obs = DBManager().get_runway_obs_recent(icao, minutes=24 * 60)
|
||||||
for r in raw_runway_obs:
|
for r in raw_runway_obs:
|
||||||
rw = r.get("runway")
|
rw = r.get("runway")
|
||||||
if not rw:
|
if not rw:
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ def _overlay_cached_runway_history_from_db(city: str, payload: Dict[str, Any]) -
|
|||||||
return payload
|
return payload
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rows = legacy_routes._CACHE_DB.get_runway_obs_recent(icao, minutes=36 * 60)
|
rows = legacy_routes._CACHE_DB.get_runway_obs_recent(icao, minutes=24 * 60)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.debug("chart runway DB overlay skipped city={} icao={}: {}", normalized_city, icao, exc)
|
logger.debug("chart runway DB overlay skipped city={} icao={}: {}", normalized_city, icao, exc)
|
||||||
return payload
|
return payload
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ def _append_amsc_runway_history_from_raw_store(
|
|||||||
if not callable(lister):
|
if not callable(lister):
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
rows = lister("amsc_awos", city, minutes=36 * 60, limit=3000)
|
rows = lister("amsc_awos", city, minutes=24 * 60, limit=1500)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.debug("latest AMSC raw history overlay skipped city={}: {}", city, exc)
|
logger.debug("latest AMSC raw history overlay skipped city={}: {}", city, exc)
|
||||||
return False
|
return False
|
||||||
|
|||||||
Reference in New Issue
Block a user