[修复] 进行中事件 duration=0 分割丢失 - 推送过 duration<=0 的事件记入 _zero_dur_ids, 下轮窗口回查已结束(duration>0)补推覆盖 Oracle; 保证 ss_motion_events 最终持有真实 duration, 分割不再跳过

This commit is contained in:
ericwyuan
2026-08-22 13:25:20 +08:00
parent cbcc5d0325
commit 177c2a83b7

View File

@@ -87,6 +87,9 @@ class MotionNotifier:
self._running = False self._running = False
self._thread = None self._thread = None
self._last_event_id = None self._last_event_id = None
# 推送过但 duration<=0动作进行中SS 尚未回填真实时长)的事件 id。
# 下轮窗口回查时若已结束duration>0补推覆盖 Oracle避免分割永远跳过。
self._zero_dur_ids = set()
self._last_poll_at = None self._last_poll_at = None
self._last_error = None self._last_error = None
self._pushed_total = 0 self._pushed_total = 0
@@ -396,7 +399,23 @@ class MotionNotifier:
events = self._fetch_events(start_ts, now) events = self._fetch_events(start_ts, now)
if events is None: if events is None:
return # 查询失败,下一轮重试 return # 查询失败,下一轮重试
# 只保留 id 大于游标的新事件SS 事件 id 单调递增) by_id = {int(e.get('id')): e for e in events if e.get('id')}
# 1) 补推:先前推送时 duration<=0动作进行中的事件现在若已结束
# SS 回填真实 duration>0重推覆盖 OracleON CONFLICT UPDATE
# 重启兜底:游标 DB 续用 → 窗口回看会把历史事件整体重推,届时同样覆盖。
if self._zero_dur_ids:
recheck = []
for eid in list(self._zero_dur_ids):
e = by_id.get(eid)
if e and int(e.get('duration') or 0) > 0:
recheck.append(e)
self._zero_dur_ids.discard(eid)
if recheck:
self.push_events_to_oracle(recheck)
logger.info(f"补推 {len(recheck)} 条已结束事件的真实 duration")
# 2) 增量推送新事件id 大于游标)
new = [e for e in events new = [e for e in events
if e.get('id') and int(e.get('id')) > (self._last_event_id or 0)] if e.get('id') and int(e.get('id')) > (self._last_event_id or 0)]
if not new: if not new:
@@ -410,6 +429,10 @@ class MotionNotifier:
# 只有推送成功的批次才推进游标;失败批次保持原地, # 只有推送成功的批次才推进游标;失败批次保持原地,
# 下一轮窗口回看会重新捞到并重试(不丢事件) # 下一轮窗口回看会重新捞到并重试(不丢事件)
cursor = max(int(e.get('id', 0)) for e in batch) cursor = max(int(e.get('id', 0)) for e in batch)
# 记录推送时仍在进行中的事件duration<=0待下轮补推真实时长
for e in batch:
if int(e.get('duration') or 0) <= 0:
self._zero_dur_ids.add(int(e.get('id')))
self._last_event_id = cursor self._last_event_id = cursor
db_layer.set_motion_cursor(str(self._last_event_id)) db_layer.set_motion_cursor(str(self._last_event_id))
@@ -479,6 +502,7 @@ class MotionNotifier:
"camera_map": {**self.camera_name_to_id, **self._ss_name_to_id}, "camera_map": {**self.camera_name_to_id, **self._ss_name_to_id},
"camera_loaded": self._camera_loaded, "camera_loaded": self._camera_loaded,
"last_event_id": self._last_event_id, "last_event_id": self._last_event_id,
"zero_dur_pending": len(self._zero_dur_ids),
"last_poll_at": self._last_poll_at.isoformat() if self._last_poll_at else None, "last_poll_at": self._last_poll_at.isoformat() if self._last_poll_at else None,
"last_error": self._last_error, "last_error": self._last_error,
"pushed_total": self._pushed_total, "pushed_total": self._pushed_total,