Refactor Uptime Kuma heartbeat implementation to use UptimeKumaMonitor class, enhancing maintainability and logging capabilities

This commit is contained in:
Misaka_Company
2026-01-15 08:52:20 +08:00
parent 2a2ec22d1c
commit 086c59cc03
3 changed files with 156 additions and 69 deletions

View File

@@ -7,7 +7,6 @@ import datetime
import urllib.parse import urllib.parse
import warnings import warnings
import time import time
import requests
import pandas as pd import pandas as pd
import numpy as np import numpy as np
from sqlalchemy import create_engine, text from sqlalchemy import create_engine, text
@@ -19,6 +18,11 @@ from log_utils import (log_error, log_warning, log_info, log_processing, log_fil
log_start, log_complete, log_stop, LoggerManager) log_start, log_complete, log_stop, LoggerManager)
from config import (DB_CONFIG, CACHE_DIR, EXCEL_CONFIGS, BATCH_SIZE, TABLE_SCHEMA, from config import (DB_CONFIG, CACHE_DIR, EXCEL_CONFIGS, BATCH_SIZE, TABLE_SCHEMA,
EXCEL_SYNC_INTERVAL, EXCEL_SYNC_UPTIME_KUMA_CONFIG) EXCEL_SYNC_INTERVAL, EXCEL_SYNC_UPTIME_KUMA_CONFIG)
from uptime_kuma_utils import UptimeKumaMonitor
# 初始化 Uptime Kuma 监控器
excel_uptime_monitor = UptimeKumaMonitor(EXCEL_SYNC_UPTIME_KUMA_CONFIG)
excel_uptime_monitor.set_logger(log_warning)
# ================= 抑制 openpyxl 的数据验证警告 ================= # ================= 抑制 openpyxl 的数据验证警告 =================
warnings.filterwarnings('ignore', category=UserWarning, module='openpyxl') warnings.filterwarnings('ignore', category=UserWarning, module='openpyxl')
@@ -295,28 +299,7 @@ class DataSynchronizer:
log_error(f"生成 ContractData 失败: {e}", exc_info=True) log_error(f"生成 ContractData 失败: {e}", exc_info=True)
# ================= Uptime Kuma 心跳 ================= # ================= Uptime Kuma 心跳 =================
# 使用 uptime_kuma_utils.UptimeKumaMonitor 替代原有实现
_last_heartbeat_time = 0
def send_heartbeat():
"""发送心跳信号到 Uptime Kuma"""
global _last_heartbeat_time
if not EXCEL_SYNC_UPTIME_KUMA_CONFIG.get('enabled', False):
return
try:
url = EXCEL_SYNC_UPTIME_KUMA_CONFIG['push_url']
params = {
'status': 'up',
'msg': 'OK',
'ping': ''
}
response = requests.get(url, params=params, timeout=5)
response.raise_for_status()
_last_heartbeat_time = time.time()
except Exception as e:
log_warning(f"心跳发送失败: {e}")
def main(): def main():
# 初始化日志管理器 # 初始化日志管理器
@@ -347,7 +330,7 @@ def main():
log_info("=" * 70) log_info("=" * 70)
# 启动时发送第一次心跳 # 启动时发送第一次心跳
send_heartbeat() excel_uptime_monitor.send_heartbeat()
try: try:
while True: while True:
@@ -365,9 +348,7 @@ def main():
# 等待下次同步,期间持续发送心跳 # 等待下次同步,期间持续发送心跳
while time.time() < next_sync_time: while time.time() < next_sync_time:
# 检查是否需要发送心跳 # 检查是否需要发送心跳
time_since_last_heartbeat = time.time() - _last_heartbeat_time excel_uptime_monitor.check_and_send_heartbeat()
if time_since_last_heartbeat >= EXCEL_SYNC_UPTIME_KUMA_CONFIG['heartbeat_interval']:
send_heartbeat()
# 短暂休眠 # 短暂休眠
time.sleep(1) time.sleep(1)
@@ -382,13 +363,7 @@ def main():
time.sleep(EXCEL_SYNC_INTERVAL) time.sleep(EXCEL_SYNC_INTERVAL)
finally: finally:
# 停止时发送心跳停止信号 # 停止时发送心跳停止信号
if EXCEL_SYNC_UPTIME_KUMA_CONFIG.get('enabled', False): excel_uptime_monitor.send_stop_signal()
try:
url = EXCEL_SYNC_UPTIME_KUMA_CONFIG['push_url']
params = {'status': 'down', 'msg': 'Service stopped'}
requests.get(url, params=params, timeout=5)
except:
pass
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -2,15 +2,19 @@ import time
import os import os
import sys import sys
import pyodbc import pyodbc
import requests
from config import SQL_SERVER_CONN, ACCESS_DRIVER, SYNC_MAPPING, POLL_INTERVAL, LOG_TABLE_CONFIG, UPTIME_KUMA_CONFIG from config import SQL_SERVER_CONN, ACCESS_DRIVER, SYNC_MAPPING, POLL_INTERVAL, LOG_TABLE_CONFIG, UPTIME_KUMA_CONFIG
import db_utils import db_utils
from log_utils import (LoggerManager, log_success, log_error, log_warning, log_info, log_processing, from log_utils import (LoggerManager, log_success, log_error, log_warning, log_info, log_processing,
log_skip, log_critical, log_start, log_stop, log_file, log_database, log_sync) log_skip, log_critical, log_start, log_stop, log_file, log_database, log_sync)
from uptime_kuma_utils import UptimeKumaMonitor
# 初始化日志管理器 # 初始化日志管理器
LoggerManager("run_incremental_sync", log_prefix="incremental") LoggerManager("run_incremental_sync", log_prefix="incremental")
# 初始化 Uptime Kuma 监控器
uptime_monitor = UptimeKumaMonitor(UPTIME_KUMA_CONFIG)
uptime_monitor.set_logger(log_warning)
# ================= 主逻辑 ================= # ================= 主逻辑 =================
def process_sync_task(): def process_sync_task():
@@ -185,29 +189,7 @@ def process_sync_task():
except: pass except: pass
# ================= Uptime Kuma 心跳 ================= # ================= Uptime Kuma 心跳 =================
# 使用 uptime_kuma_utils.UptimeKumaMonitor 替代原有实现
_last_heartbeat_time = 0
def send_heartbeat():
"""发送心跳信号到 Uptime Kuma"""
global _last_heartbeat_time
if not UPTIME_KUMA_CONFIG.get('enabled', False):
return
try:
url = UPTIME_KUMA_CONFIG['push_url']
params = {
'status': 'up',
'msg': 'OK',
'ping': ''
}
response = requests.get(url, params=params, timeout=5)
response.raise_for_status()
_last_heartbeat_time = time.time()
except Exception as e:
# 心跳失败不影响主逻辑,仅记录日志
log_warning(f"心跳发送失败: {e}")
if __name__ == "__main__": if __name__ == "__main__":
log_start("增量同步服务已启动 (配置驱动模式)") log_start("增量同步服务已启动 (配置驱动模式)")
@@ -218,7 +200,7 @@ if __name__ == "__main__":
log_info("=" * 70) log_info("=" * 70)
# 启动时发送第一次心跳 # 启动时发送第一次心跳
send_heartbeat() uptime_monitor.send_heartbeat()
try: try:
while True: while True:
@@ -226,9 +208,7 @@ if __name__ == "__main__":
has_work = process_sync_task() has_work = process_sync_task()
# 检查是否需要发送心跳 # 检查是否需要发送心跳
time_since_last_heartbeat = time.time() - _last_heartbeat_time uptime_monitor.check_and_send_heartbeat()
if time_since_last_heartbeat >= UPTIME_KUMA_CONFIG['heartbeat_interval']:
send_heartbeat()
# 如果有工作,说明可能还有积压,休息短一点(0.1s) # 如果有工作,说明可能还有积压,休息短一点(0.1s)
# 如果没工作,休息标准间隔(5s) # 如果没工作,休息标准间隔(5s)
@@ -243,10 +223,4 @@ if __name__ == "__main__":
time.sleep(5) time.sleep(5)
finally: finally:
# 停止时发送心跳停止信号(可选) # 停止时发送心跳停止信号(可选)
if UPTIME_KUMA_CONFIG.get('enabled', False): uptime_monitor.send_stop_signal()
try:
url = UPTIME_KUMA_CONFIG['push_url']
params = {'status': 'down', 'msg': 'Service stopped'}
requests.get(url, params=params, timeout=5)
except:
pass

138
uptime_kuma_utils.py Normal file
View File

@@ -0,0 +1,138 @@
"""
Uptime Kuma 心跳监控工具
用于向 Uptime Kuma 服务发送心跳信号,监控服务运行状态。
"""
import time
import requests
class UptimeKumaMonitor:
"""
Uptime Kuma 心跳监控器
示例:
from uptime_kuma_utils import UptimeKumaMonitor
# 初始化监控器
monitor = UptimeKumaMonitor({
'enabled': True,
'push_url': 'https://uptimekuma.example.com/api/push/xxx',
'heartbeat_interval': 59
})
# 启动时发送首次心跳
monitor.send_heartbeat()
# 主循环中定期发送心跳
while True:
monitor.check_and_send_heartbeat()
# ... 执行任务 ...
# 停止时发送停止信号
monitor.send_stop_signal()
"""
def __init__(self, config):
"""
初始化监控器
Args:
config (dict): 配置字典,包含:
- enabled (bool): 是否启用心跳
- push_url (str): Uptime Kuma 推送 URL
- heartbeat_interval (int): 心跳间隔(秒)
"""
self.config = config or {}
self.enabled = self.config.get('enabled', False)
self.push_url = self.config.get('push_url')
self.heartbeat_interval = self.config.get('heartbeat_interval', 60)
self._last_heartbeat_time = 0
self._logger = None
def set_logger(self, logger_func):
"""
设置日志记录函数
Args:
logger_func: 日志记录函数,如 log_warning, log_info 等
"""
self._logger = logger_func
def _log(self, func_name, message):
"""内部日志记录方法"""
if self._logger:
self._logger(message)
def send_heartbeat(self):
"""
发送心跳信号到 Uptime Kuma
Returns:
bool: 是否成功发送
"""
if not self.enabled or not self.push_url:
return False
try:
params = {
'status': 'up',
'msg': 'OK',
'ping': ''
}
response = requests.get(self.push_url, params=params, timeout=5)
response.raise_for_status()
self._last_heartbeat_time = time.time()
return True
except Exception as e:
self._log('warning', f"心跳发送失败: {e}")
return False
def send_stop_signal(self):
"""
发送停止信号到 Uptime Kuma
Returns:
bool: 是否成功发送
"""
if not self.enabled or not self.push_url:
return False
try:
params = {'status': 'down', 'msg': 'Service stopped'}
response = requests.get(self.push_url, params=params, timeout=5)
response.raise_for_status()
return True
except Exception as e:
# 停止信号失败不影响主逻辑
return False
def check_and_send_heartbeat(self):
"""
检查是否需要发送心跳,如果需要则发送
Returns:
bool: 是否发送了心跳
"""
if not self.enabled:
return False
time_since_last = time.time() - self._last_heartbeat_time
if time_since_last >= self.heartbeat_interval:
return self.send_heartbeat()
return False
def get_time_since_last_heartbeat(self):
"""
获取距离上次心跳的时间(秒)
Returns:
float: 距离上次心跳的秒数
"""
return time.time() - self._last_heartbeat_time
@property
def last_heartbeat_time(self):
"""获取上次心跳时间戳"""
return self._last_heartbeat_time