File size: 2,739 Bytes
c50496f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | """
保活服务模块
定期向配置的URL发送GET请求,保持服务在线
未配置保活URL时不启动任何任务,零资源占用
"""
import asyncio
from typing import Optional
from config import get_keepalive_interval, get_keepalive_url
from log import log
from src.httpx_client import get_async
class KeepAliveService:
"""保活服务:定期向指定URL发送GET请求"""
def __init__(self):
self._task: Optional[asyncio.Task] = None
async def _run(self, url: str, interval: int):
"""保活循环,读取到有效URL才会被调用"""
log.info(f"[KeepAlive] 保活任务启动,URL={url},间隔={interval}s")
while True:
try:
response = await get_async(url, timeout=30.0)
log.info(f"[KeepAlive] GET {url} -> {response.status_code}")
except asyncio.CancelledError:
raise
except Exception as e:
log.warning(f"[KeepAlive] GET {url} 失败: {e}")
try:
await asyncio.sleep(interval)
except asyncio.CancelledError:
raise
async def start(self):
"""
启动保活服务。
仅当配置了有效的保活URL时才创建后台任务,否则零开销。
"""
if self._task and not self._task.done():
# 已有任务在运行,不重复启动
return
url = await get_keepalive_url()
interval = await get_keepalive_interval()
if not url or not url.strip():
log.debug("[KeepAlive] 未配置保活URL,保活服务不启动")
return
if interval <= 0:
log.warning(f"[KeepAlive] 保活间隔无效({interval}),保活服务不启动")
return
self._task = asyncio.create_task(
self._run(url.strip(), interval), name="keepalive_service"
)
async def stop(self):
"""停止保活服务"""
if self._task and not self._task.done():
self._task.cancel()
try:
await self._task
except asyncio.CancelledError:
pass
log.info("[KeepAlive] 保活服务已停止")
self._task = None
async def restart(self):
"""
重启保活服务。
配置变更时调用,会停止旧任务并根据最新配置决定是否启动新任务。
"""
await self.stop()
await self.start()
@property
def is_running(self) -> bool:
"""当前保活任务是否在运行"""
return self._task is not None and not self._task.done()
# 全局保活服务实例
keepalive_service = KeepAliveService()
|