Deploy to new ubuntu machine
This commit is contained in:
@@ -17,6 +17,7 @@ from app.db import (
|
||||
measure_snapshot_deliverable,
|
||||
save_measure_snapshot,
|
||||
)
|
||||
from app.logging_config import new_run_id, stage
|
||||
from app.services import measure as measure_svc
|
||||
from app.settings import Settings
|
||||
from app.state import app_state
|
||||
@@ -94,64 +95,76 @@ async def _run_single_svo_measure(
|
||||
fish_output_root = settings.measure_output_root / f"fish{fish_id}"
|
||||
fish_output_root.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
logger.info(
|
||||
"[measure-watch] segment inference fish_id={} svo={}",
|
||||
fish_id,
|
||||
svo.name,
|
||||
try:
|
||||
size_mb = svo.stat().st_size / (1024 * 1024)
|
||||
except OSError:
|
||||
size_mb = 0.0
|
||||
rid = new_run_id("measure_watch")
|
||||
log = logger.bind(pipeline="measure_watch", run_id=rid, fish_id=fish_id)
|
||||
log.info(
|
||||
"[测量监控] 触发分段测量 | fish_id={} | svo={} | 大小={:.1f} MB",
|
||||
fish_id, svo.name, size_mb,
|
||||
)
|
||||
|
||||
async with app_state.measure_lock:
|
||||
app_state.measure_status = "running"
|
||||
try:
|
||||
with stage(
|
||||
f"分段测量 fish{fish_id}/{svo.name}",
|
||||
pipeline="measure_watch",
|
||||
step="segment_total",
|
||||
run_id=rid,
|
||||
source=svo.name,
|
||||
fish_id=fish_id,
|
||||
metrics={"fish_id": fish_id, "svo_size_mb": round(size_mb, 2)},
|
||||
):
|
||||
def _run():
|
||||
with app_state.measure_thread_lock:
|
||||
return measure_svc.run_full_measure(
|
||||
svo, settings, output_root=fish_output_root, run_id=rid
|
||||
)
|
||||
|
||||
def _run():
|
||||
with app_state.measure_thread_lock:
|
||||
return measure_svc.run_full_measure(
|
||||
svo, settings, output_root=fish_output_root
|
||||
)
|
||||
snap = await to_thread(_run)
|
||||
|
||||
snap = await to_thread(_run)
|
||||
|
||||
snap = measure_svc.tag_measure_snapshot_meta(
|
||||
snap,
|
||||
measurement_phase="segment",
|
||||
fish_folder=str(fish_folder),
|
||||
segment_source=str(svo.resolve()),
|
||||
)
|
||||
|
||||
if measure_snapshot_deliverable(snap):
|
||||
save_measure_snapshot(
|
||||
settings,
|
||||
snap = measure_svc.tag_measure_snapshot_meta(
|
||||
snap,
|
||||
source_path=str(svo.resolve()),
|
||||
client_id=None,
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"[measure-watch] no deliverable measure rows for fish_id={} svo={}, skip SQLite",
|
||||
fish_id,
|
||||
svo.name,
|
||||
measurement_phase="segment",
|
||||
fish_folder=str(fish_folder),
|
||||
segment_source=str(svo.resolve()),
|
||||
)
|
||||
|
||||
if measure_snapshot_deliverable(snap):
|
||||
save_measure_snapshot(
|
||||
settings,
|
||||
snap,
|
||||
source_path=str(svo.resolve()),
|
||||
client_id=None,
|
||||
)
|
||||
else:
|
||||
log.warning(
|
||||
"[测量监控] 无可投递结果,跳过写库 | fish_id={} | svo={}",
|
||||
fish_id, svo.name,
|
||||
)
|
||||
|
||||
app_state.measure_status = "idle"
|
||||
processed.add(key)
|
||||
if settings.measure_watch_use_state_file:
|
||||
add_watch_processed(settings, key, "measure")
|
||||
|
||||
r0 = snap.result[0] if snap.result else {}
|
||||
logger.info(
|
||||
"[measure-watch] segment done: fish_id={} svo={} weight={!r}",
|
||||
log.info(
|
||||
"[测量监控] 分段完成 | fish_id={} | svo={} | 体重={} g | 体长={} mm | 置信(*)={}",
|
||||
fish_id,
|
||||
svo.name,
|
||||
r0.get("weight", ""),
|
||||
r0.get("weight", "") or "-",
|
||||
r0.get("length", "") or "-",
|
||||
"是" if snap.star else "否",
|
||||
)
|
||||
|
||||
except (RuntimeError, FileNotFoundError) as e:
|
||||
logger.warning(
|
||||
"[measure-watch] measure failed fish_id={} svo={}: {}",
|
||||
fish_id,
|
||||
svo.name,
|
||||
e,
|
||||
log.warning(
|
||||
"[测量监控] 分段测量失败 | fish_id={} | svo={} | {}: {}",
|
||||
fish_id, svo.name, type(e).__name__, e,
|
||||
)
|
||||
app_state.measure_status = "idle"
|
||||
processed.add(key)
|
||||
@@ -159,11 +172,9 @@ async def _run_single_svo_measure(
|
||||
add_watch_processed(settings, key, "measure")
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
"[measure-watch] error fish_id={} svo={}: {}",
|
||||
fish_id,
|
||||
svo.name,
|
||||
e,
|
||||
log.exception(
|
||||
"[测量监控] 分段测量异常 | fish_id={} | svo={} | {}",
|
||||
fish_id, svo.name, e,
|
||||
)
|
||||
app_state.measure_status = "idle"
|
||||
processed.add(key)
|
||||
@@ -181,82 +192,95 @@ async def _run_final_aggregate(
|
||||
) -> None:
|
||||
fish_folder = svo_list[0].parent.resolve()
|
||||
|
||||
logger.info(
|
||||
"[measure-watch] final aggregate fish_id={} {} segment(s)",
|
||||
fish_id,
|
||||
len(svo_list),
|
||||
rid = new_run_id("measure_watch_final")
|
||||
log = logger.bind(pipeline="measure_watch", run_id=rid, fish_id=fish_id)
|
||||
log.info(
|
||||
"[测量监控] 触发齐套聚合 | fish_id={} | 段数={} | 文件夹={}",
|
||||
fish_id, len(svo_list), fish_folder,
|
||||
)
|
||||
|
||||
async with app_state.measure_lock:
|
||||
app_state.measure_status = "running"
|
||||
try:
|
||||
|
||||
def _reload():
|
||||
return measure_svc.reload_segment_snapshots_for_aggregate(
|
||||
svo_list, fish_id, settings
|
||||
)
|
||||
|
||||
pairs = await to_thread(_reload)
|
||||
contributing_svos = [p[0] for p in pairs]
|
||||
segments = [p[1] for p in pairs]
|
||||
paths_joined = "|".join(sorted(str(p.resolve()) for p in contributing_svos))
|
||||
|
||||
snap = measure_svc.build_measure_snapshot_aggregate(
|
||||
segments,
|
||||
fish_id,
|
||||
settings,
|
||||
contributing_svos=contributing_svos,
|
||||
fish_folder=str(fish_folder),
|
||||
segment_source_paths=paths_joined,
|
||||
)
|
||||
|
||||
if measure_snapshot_deliverable(snap):
|
||||
try:
|
||||
v_left, v_right = await to_thread(
|
||||
measure_svc.generate_aggregate_preview_media,
|
||||
contributing_svos,
|
||||
snap,
|
||||
fish_id,
|
||||
settings,
|
||||
final_key=final_key,
|
||||
with stage(
|
||||
f"齐套聚合 fish{fish_id}({len(svo_list)} 段)",
|
||||
pipeline="measure_watch",
|
||||
step="final_total",
|
||||
run_id=rid,
|
||||
source=str(fish_folder),
|
||||
fish_id=fish_id,
|
||||
metrics={
|
||||
"fish_id": fish_id,
|
||||
"segment_count": len(svo_list),
|
||||
"aggregate_mode": settings.measure_final_aggregate_mode,
|
||||
},
|
||||
):
|
||||
def _reload():
|
||||
return measure_svc.reload_segment_snapshots_for_aggregate(
|
||||
svo_list, fish_id, settings
|
||||
)
|
||||
snap.video_left = v_left
|
||||
snap.video_right = v_right
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"[measure-watch] final preview generate failed fish_id={}: {}",
|
||||
fish_id,
|
||||
e,
|
||||
)
|
||||
save_measure_snapshot(
|
||||
settings,
|
||||
snap,
|
||||
source_path=f"aggregate:{final_key}",
|
||||
client_id=None,
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"[measure-watch] final not deliverable for fish_id={}, skip SQLite",
|
||||
|
||||
pairs = await to_thread(_reload)
|
||||
contributing_svos = [p[0] for p in pairs]
|
||||
segments = [p[1] for p in pairs]
|
||||
paths_joined = "|".join(sorted(str(p.resolve()) for p in contributing_svos))
|
||||
|
||||
snap = measure_svc.build_measure_snapshot_aggregate(
|
||||
segments,
|
||||
fish_id,
|
||||
settings,
|
||||
contributing_svos=contributing_svos,
|
||||
fish_folder=str(fish_folder),
|
||||
segment_source_paths=paths_joined,
|
||||
)
|
||||
|
||||
if measure_snapshot_deliverable(snap):
|
||||
try:
|
||||
v_left, v_right = await to_thread(
|
||||
measure_svc.generate_aggregate_preview_media,
|
||||
contributing_svos,
|
||||
snap,
|
||||
fish_id,
|
||||
settings,
|
||||
final_key=final_key,
|
||||
run_id=rid,
|
||||
)
|
||||
snap.video_left = v_left
|
||||
snap.video_right = v_right
|
||||
except Exception as e:
|
||||
log.warning(
|
||||
"[测量监控] 齐套预览视频生成失败 | fish_id={} | {}",
|
||||
fish_id, e,
|
||||
)
|
||||
save_measure_snapshot(
|
||||
settings,
|
||||
snap,
|
||||
source_path=f"aggregate:{final_key}",
|
||||
client_id=None,
|
||||
)
|
||||
else:
|
||||
log.warning(
|
||||
"[测量监控] 齐套结果无可投递行,跳过写库 | fish_id={}",
|
||||
fish_id,
|
||||
)
|
||||
|
||||
app_state.measure_status = "idle"
|
||||
processed.add(final_key)
|
||||
if settings.measure_watch_use_state_file:
|
||||
add_watch_processed(settings, final_key, "measure")
|
||||
|
||||
r0 = snap.result[0] if snap.result else {}
|
||||
logger.info(
|
||||
"[measure-watch] final done: fish_id={} weight={!r}",
|
||||
log.info(
|
||||
"[测量监控] 齐套完成 | fish_id={} | 体重={} g | 体长={} mm | 置信(*)={}",
|
||||
fish_id,
|
||||
r0.get("weight", ""),
|
||||
r0.get("weight", "") or "-",
|
||||
r0.get("length", "") or "-",
|
||||
"是" if snap.star else "否",
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
"[measure-watch] final aggregate failed fish_id={}: {}",
|
||||
fish_id,
|
||||
e,
|
||||
log.exception(
|
||||
"[测量监控] 齐套聚合异常 | fish_id={} | {}", fish_id, e,
|
||||
)
|
||||
app_state.measure_status = "idle"
|
||||
processed.add(final_key)
|
||||
@@ -352,7 +376,9 @@ async def run_measure_watch_loop(settings: Settings) -> None:
|
||||
assert settings.measure_watch_dir is not None
|
||||
wd = settings.measure_watch_dir
|
||||
if not wd.is_dir():
|
||||
logger.warning("[measure-watch] skip: not a directory: {}", wd)
|
||||
logger.bind(pipeline="measure_watch").warning(
|
||||
"[测量监控] 启动跳过:路径不是目录 {}", wd
|
||||
)
|
||||
return
|
||||
|
||||
state_file = _state_path(settings)
|
||||
@@ -364,8 +390,8 @@ async def run_measure_watch_loop(settings: Settings) -> None:
|
||||
stability = {} # type: Dict[str, Tuple[int, int]]
|
||||
final_stability = {} # type: Dict[str, Tuple[Tuple[Tuple[str, int], ...], int]]
|
||||
|
||||
logger.info(
|
||||
"[measure-watch] watching {} (poll={}s, stable_polls={}, aggregate={}, state={} {})",
|
||||
logger.bind(pipeline="measure_watch").info(
|
||||
"[测量监控] 监控目录已启动 | dir={} | poll={}s | stable_polls={} | aggregate={} | state={} {}",
|
||||
wd,
|
||||
settings.measure_watch_poll_interval,
|
||||
settings.measure_watch_stable_polls,
|
||||
|
||||
Reference in New Issue
Block a user