fix(stability): 補強 scheduler 例外記錄
All checks were successful
CD Pipeline / deploy (push) Successful in 1m36s

This commit is contained in:
OoO
2026-04-30 10:28:37 +08:00
parent 18b0fa8af2
commit e73cd6e6a3
9 changed files with 86 additions and 34 deletions

View File

@@ -151,8 +151,11 @@ def managed_scraper_resources(window_size='1920,5000', debug=False, timeout=45,
if driver:
try:
driver.quit()
except:
pass
except Exception as cleanup_error:
logging.warning(
f"[Scraper] [Resource] ⚠️ Chrome 初始化失敗後關閉 driver 也失敗 | Error: {cleanup_error}",
exc_info=True,
)
driver = None
if retry_count <= max_retries:
@@ -178,8 +181,11 @@ def managed_scraper_resources(window_size='1920,5000', debug=False, timeout=45,
# 先關閉所有視窗
try:
driver.close()
except:
pass
except Exception as close_error:
logging.debug(
f"[Scraper] [Resource] Chrome 視窗關閉失敗但繼續 quit | Error: {close_error}",
exc_info=True,
)
# 再退出 driver
driver.quit()
except Exception as quit_error:
@@ -188,14 +194,20 @@ def managed_scraper_resources(window_size='1920,5000', debug=False, timeout=45,
try:
import subprocess
subprocess.run(['pkill', '-f', 'chrome.*--headless'], timeout=5, capture_output=True)
except:
pass
except Exception as pkill_error:
logging.warning(
f"[Scraper] [Resource] ⚠️ Chrome 強制清理失敗 | Error: {pkill_error}",
exc_info=True,
)
if session:
try:
session.close()
except:
pass
except Exception as session_error:
logging.warning(
f"[Scraper] [Resource] ⚠️ DB session 關閉失敗 | Error: {session_error}",
exc_info=True,
)
def run_momo_task():
@@ -206,8 +218,11 @@ def run_momo_task():
if is_task_paused("run_momo_task"):
logging.info("[Crawler] [MOMO] ⏸️ 任務被 HITL 暫停中,本次跳過")
return
except Exception:
pass # agent_actions 未就緒時不阻塞排程
except Exception as pause_check_error:
logging.debug(
f"[Crawler] [MOMO] HITL 暫停檢查失敗但繼續排程 | Error: {pause_check_error}",
exc_info=True,
)
try:
# V-New: 每次執行任務時,動態從 JSON 檔案重新讀取分類
@@ -517,8 +532,11 @@ def run_edm_task(lpn_code="O1K5FBOqsvN"):
if "/" in txt and ":" in txt: # 增強判斷:需包含日期斜線與時間冒號
activity_time_text = txt
break
except:
pass
except Exception as activity_time_error:
logging.debug(
f"[Crawler] [EDM] 活動時間文字解析失敗但繼續 | Error: {activity_time_error}",
exc_info=True,
)
if not activity_time_text:
activity_time_text = activity_name
logging.info(f"[Crawler] [EDM] ⏰ 抓取到的全站活動時間: {activity_time_text}")
@@ -553,8 +571,11 @@ def run_edm_task(lpn_code="O1K5FBOqsvN"):
# 嘗試抓取 .dateTime若無則嘗試找包含 "開搶" 的元素
dt_el = parent.find_element(By.CSS_SELECTOR, ".dateTime")
session_time_text = dt_el.text.strip()
except:
pass
except Exception as session_time_error:
logging.debug(
f"[Crawler] [EDM] 區塊時間說明解析失敗但繼續 | Block: {i+1} | Error: {session_time_error}",
exc_info=True,
)
time_el = parent.find_element(By.CSS_SELECTOR, ".dateTime .time span")
if time_el:
@@ -642,9 +663,10 @@ def run_edm_task(lpn_code="O1K5FBOqsvN"):
price_text = price_el.text.replace(",", "").strip()
if price_text.isdigit():
price = int(price_text)
except Exception:
logging.info(f"[Crawler] [EDM] 找不到價格元素 | i_code: {i_code} | Info: 可能已售完")
pass # price 保持為 None
except Exception as price_error:
logging.info(
f"[Crawler] [EDM] 找不到價格元素 | i_code: {i_code} | Info: 可能已售完 | Error: {price_error}"
)
# V9.91: 解析折扣數
discount_text = ""
@@ -666,8 +688,11 @@ def run_edm_task(lpn_code="O1K5FBOqsvN"):
qty_text = qty_span.text.strip().replace(",", "")
if qty_text.isdigit():
remain_qty = int(qty_text)
except:
pass
except Exception as remain_qty_error:
logging.debug(
f"[Crawler] [EDM] 倒數組數解析失敗但繼續 | i_code: {i_code} | Error: {remain_qty_error}",
exc_info=True,
)
current_scan_icodes.add((i_code, time_slot))
@@ -1810,8 +1835,11 @@ def run_auto_import_task():
if is_task_paused("run_auto_import_task"):
logging.info("[Scheduler] [AutoImport] ⏸️ 任務被 HITL 暫停中,本次跳過")
return
except Exception:
pass
except Exception as pause_check_error:
logging.debug(
f"[Scheduler] [AutoImport] HITL 暫停檢查失敗但繼續排程 | Error: {pause_check_error}",
exc_info=True,
)
try:
from services.import_service import import_service
@@ -2226,8 +2254,11 @@ def run_db_backup_task():
metadata={"status": "success", "size_kb": size_kb, "deleted_old": deleted_count},
ai_model="scheduler",
)
except Exception:
pass
except Exception as insight_error:
logging.warning(
f"[Scheduler] [Backup] ⚠️ 備份成功 insight 寫入失敗但繼續通知 | Error: {insight_error}",
exc_info=True,
)
else:
msg = (
f"🚨 資料庫備份失敗 ({now_str})\n"
@@ -2262,8 +2293,11 @@ def run_db_backup_task():
metadata={"status": "failed", "error": result.get("error")},
ai_model="scheduler",
)
except Exception:
pass
except Exception as insight_error:
logging.warning(
f"[Scheduler] [Backup] ⚠️ 備份失敗 insight 寫入失敗但繼續通知 | Error: {insight_error}",
exc_info=True,
)
notifier._send_telegram_messages([msg])
@@ -2288,8 +2322,11 @@ def run_db_backup_task():
NotificationManager()._send_telegram_messages([
f"🚨 DB 備份排程異常\n錯誤:{e}"
])
except Exception:
pass
except Exception as notify_error:
logging.warning(
f"[Scheduler] [Backup] ⚠️ 備份異常 Telegram 通知失敗 | Error: {notify_error}",
exc_info=True,
)
def run_backup_monitor_task():
@@ -2362,8 +2399,11 @@ def run_backup_monitor_task():
metadata={"alert": True, "reason": alert_reason, "latest_file": info.get("filename")},
ai_model="scheduler",
)
except Exception:
pass
except Exception as insight_error:
logging.warning(
f"[Scheduler] [BackupMonitor] ⚠️ 備份監控 insight 寫入失敗但繼續 | Error: {insight_error}",
exc_info=True,
)
else:
created_at = info.get("created_at")
logging.info(f"[Scheduler] [BackupMonitor] ✅ 備份狀態正常 | 最新: {info.get('filename')} @ {created_at}")