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()