diff --git a/routes/openclaw_bot_routes.py b/routes/openclaw_bot_routes.py index 0c614e2..3416aab 100644 --- a/routes/openclaw_bot_routes.py +++ b/routes/openclaw_bot_routes.py @@ -3300,9 +3300,32 @@ def send_daily_excel(): sys_log.error(f"[AutoExcel] {e}") +_sched_lock_fh = None # 持有鎖的 file handle,進程退出時自動釋放 + + def start_scheduler(): - """啟動排程(Flask app 啟動後呼叫)""" - global _scheduler + """啟動排程(Flask app 啟動後呼叫) + 使用 fcntl exclusive lock 確保 Gunicorn 多 worker 環境下只有一個 worker 運行排程。 + """ + global _scheduler, _sched_lock_fh + import fcntl, atexit + + lock_path = '/tmp/openclaw_scheduler.lock' + try: + _sched_lock_fh = open(lock_path, 'w') + fcntl.flock(_sched_lock_fh.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) + except OSError: + sys_log.info("[OpenClawBot] Scheduler lock busy — another worker owns it, skipping") + return + + @atexit.register + def _release_sched_lock(): + try: + fcntl.flock(_sched_lock_fh.fileno(), fcntl.LOCK_UN) + _sched_lock_fh.close() + except Exception: + pass + try: from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.triggers.cron import CronTrigger @@ -3315,7 +3338,7 @@ def start_scheduler(): _scheduler.add_job(send_weekly_report, CronTrigger(day_of_week='mon', hour=9, minute=0)) _scheduler.add_job(check_anomalies, CronTrigger(hour='9,12,15,18', minute=0)) _scheduler.start() - sys_log.info("[OpenClawBot] Scheduler started ✓ (competitor/morning/excel/evening/weekly/anomaly)") + sys_log.info("[OpenClawBot] Scheduler started ✓ pid=%d (competitor/morning/excel/evening/weekly/anomaly)", os.getpid()) except ImportError: sys_log.warning("[OpenClawBot] APScheduler 未安裝 — 排程功能停用") except Exception as e: