Files
ewoooc/run_scheduler.py
ogt 676c711e7a
Some checks are pending
CD Pipeline / deploy (push) Waiting to run
feat: AI 治理完備 V10.3 — 技術債清零 + DB 備份機制 + 備份 AI 監控
技術債清零 (2026-04-19):
- migrations/010: ai_insights 補 decay_exempt/avg_quality/status/ai_model/feedback 欄位
- migrations/011: embedding_retry_queue 持久化表 (ADR-009)
- migrations/012: backup_log 備份記錄表
- services/openclaw_learning_service: 記憶體 Queue → DB retry queue,時間衰減 RAG
- services/nemoton_dispatcher_service: 三個 tool 強制雙寫 ai_insights (_sink_insight_to_km)
- services/import_service: Excel 前置欄位防禦(商品名稱類 + 業績金額類)
- services/ollama_service: generate_embedding 新增 EMBEDDING_HOST env,embedding 永遠走 192.168.0.111
- SYSTEM_VERSION: V9.4 → V10.3

DB 備份機制:
- scripts/pg_backup.sh: host-level pg_dump 備份腳本,cron 每日 02:00,保留 7 天,Telegram 通知
- services/db_backup_service.py: Python 備份 service,寫入 backup_log
- scheduler: run_db_backup_task (02:00) + run_backup_monitor_task (每 6h AI Agent 監控)
- Dockerfile: 加入 postgresql-client

文件:
- CLAUDE.md: 環境架構依 ADR-008 實地重寫,含完整 SSH/Docker 部署 SOP
- PROJECT_CONSTITUTION.md: 內容已整合入 CLAUDE.md,刪除重複檔案

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 02:03:45 +08:00

139 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
MOMO Pro System - 獨立排程服務
此腳本用於 K8s scheduler 部署,獨立運行排程任務
避免 Gunicorn 多 worker 重複執行的問題
"""
import os
import sys
import time
import logging
import schedule
from datetime import datetime
# 設定日誌
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
handlers=[
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger(__name__)
# 確保能夠導入專案模組
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, BASE_DIR)
# 設定環境變數(如果未設定)
if not os.environ.get('DATABASE_URL'):
os.environ['DATABASE_URL'] = 'sqlite:///data/momo_database.db'
def main():
"""主函數:初始化並運行排程"""
logger.info("=" * 60)
logger.info("🚀 MOMO Pro Scheduler 啟動中...")
logger.info("=" * 60)
# 導入排程任務
try:
from scheduler import (
run_momo_task,
run_edm_task,
run_festival_task,
run_auto_import_task,
run_whitepage_check,
run_competitor_price_feeder_task,
run_icaim_analysis_task,
run_weekly_strategy_task,
run_db_backup_task,
run_backup_monitor_task,
)
logger.info("✅ 排程任務模組載入成功")
except ImportError as e:
logger.error(f"❌ 無法載入排程模組: {e}")
sys.exit(1)
# 檢查是否停用自動匯入
disable_auto_import = os.environ.get('DISABLE_AUTO_IMPORT', 'false').lower() == 'true'
# 設定排程
schedule.every(1).hours.do(run_momo_task)
logger.info("📅 已設定:每小時執行主站爬蟲任務")
schedule.every(1).hours.do(run_edm_task)
logger.info("📅 已設定:每小時執行 EDM 爬蟲任務")
schedule.every(1).hours.do(run_festival_task)
logger.info("📅 已設定:每 6 小時執行購物節爬蟲任務")
if not disable_auto_import:
schedule.every(30).minutes.do(run_auto_import_task)
logger.info("📅 已設定:每 30 分鐘執行 Google Drive 自動匯入任務")
else:
logger.info("⚠️ 自動匯入已停用 (DISABLE_AUTO_IMPORT=true)")
schedule.every(30).minutes.do(run_whitepage_check)
logger.info("📅 已設定:每 30 分鐘執行網頁白頁監控任務")
schedule.every(4).hours.do(run_competitor_price_feeder_task)
logger.info("📅 已設定:每 4 小時執行 PChome 競品價格抓取任務")
schedule.every(6).hours.do(run_icaim_analysis_task)
logger.info("📅 已設定:每 6 小時執行 ICAIM 競價情報分析Hermes→NemoTron→Telegram")
schedule.every().monday.at("07:00").do(run_weekly_strategy_task)
logger.info("📅 已設定:每週一 07:00 執行 Gemini 策略師週報任務")
schedule.every().day.at("02:00").do(run_db_backup_task)
logger.info("📅 已設定:每日 02:00 執行 PostgreSQL 資料庫備份")
schedule.every(6).hours.do(run_backup_monitor_task)
logger.info("📅 已設定:每 6 小時執行備份健康監控AI Agent 跟進)")
logger.info("=" * 60)
logger.info("✅ 排程器已啟動,等待任務執行...")
logger.info("=" * 60)
# 啟動時立即執行一次自動匯入(如果未停用)
if not disable_auto_import:
logger.info("🔄 啟動時執行一次自動匯入...")
try:
run_auto_import_task()
except Exception as e:
logger.error(f"❌ 啟動時自動匯入失敗: {e}")
# 啟動時立即執行一次爬蟲任務
logger.info("🔄 啟動時執行一次 MOMO 商品爬蟲...")
try:
run_momo_task()
except Exception as e:
logger.error(f"❌ 啟動時 MOMO 爬蟲失敗: {e}")
logger.info("🔄 啟動時執行一次 EDM 活動爬蟲...")
try:
run_edm_task()
except Exception as e:
logger.error(f"❌ 啟動時 EDM 爬蟲失敗: {e}")
logger.info("🔄 啟動時執行一次購物節爬蟲...")
try:
run_festival_task()
except Exception as e:
logger.error(f"❌ 啟動時購物節爬蟲失敗: {e}")
# 運行排程循環
while True:
try:
schedule.run_pending()
time.sleep(1)
except KeyboardInterrupt:
logger.info("🛑 收到中斷信號,排程器停止")
break
except Exception as e:
logger.error(f"❌ 排程執行錯誤: {e}")
time.sleep(5) # 發生錯誤時等待 5 秒後繼續
if __name__ == "__main__":
main()