Add support for Kuma push monitoring with retry logic
This commit is contained in:
65
listen.py
65
listen.py
@@ -29,6 +29,8 @@ ESP_API_KEY = os.getenv("ESP_API_KEY", "")
|
|||||||
KUMA_URL = os.getenv("KUMA_URL")
|
KUMA_URL = os.getenv("KUMA_URL")
|
||||||
KUMA_KEY = os.getenv("KUMA_KEY")
|
KUMA_KEY = os.getenv("KUMA_KEY")
|
||||||
POLL_INTERVAL = int(os.getenv("POLL_INTERVAL", "30"))
|
POLL_INTERVAL = int(os.getenv("POLL_INTERVAL", "30"))
|
||||||
|
KUMA_PUSH_URL = os.getenv("KUMA_PUSH_URL")
|
||||||
|
KUMA_PUSH_INTERVAL = int(os.getenv("KUMA_PUSH_INTERVAL", "60"))
|
||||||
|
|
||||||
|
|
||||||
class UptimeKumaMonitor:
|
class UptimeKumaMonitor:
|
||||||
@@ -271,6 +273,51 @@ class ESP32Controller:
|
|||||||
logger.info("Disconnected from ESP32")
|
logger.info("Disconnected from ESP32")
|
||||||
|
|
||||||
|
|
||||||
|
async def push_to_kuma(session: aiohttp.ClientSession, url: str):
|
||||||
|
"""Send a GET request to the Kuma push URL with retry logic"""
|
||||||
|
try:
|
||||||
|
# First attempt
|
||||||
|
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||||||
|
logger.info(f"Kuma push: status {resp.status}")
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Kuma push failed: {e} (retrying in 15s)")
|
||||||
|
await asyncio.sleep(15)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Retry attempt
|
||||||
|
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||||||
|
logger.info(f"Kuma push retry succeeded: status {resp.status}")
|
||||||
|
except Exception as retry_e:
|
||||||
|
logger.error(f"Kuma push retry failed: {retry_e}")
|
||||||
|
|
||||||
|
|
||||||
|
async def kuma_push_monitor(
|
||||||
|
url: str, interval: int, session: Optional[aiohttp.ClientSession] = None
|
||||||
|
):
|
||||||
|
"""Periodically send GET requests to the Kuma push URL.
|
||||||
|
|
||||||
|
If a session is provided, it will be reused and not closed here.
|
||||||
|
If no session is provided, this function will create one and ensure it is
|
||||||
|
properly closed, even if the task is cancelled.
|
||||||
|
"""
|
||||||
|
own_session = False
|
||||||
|
if session is None:
|
||||||
|
session = aiohttp.ClientSession()
|
||||||
|
own_session = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
await push_to_kuma(session, url)
|
||||||
|
await asyncio.sleep(interval)
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
# Ensure proper cleanup on cancellation before propagating
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
if own_session and not session.closed:
|
||||||
|
await session.close()
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
"""Main monitoring loop"""
|
"""Main monitoring loop"""
|
||||||
|
|
||||||
@@ -285,12 +332,13 @@ async def main():
|
|||||||
|
|
||||||
if not KUMA_KEY:
|
if not KUMA_KEY:
|
||||||
logger.error("KUMA_KEY not set in environment")
|
logger.error("KUMA_KEY not set in environment")
|
||||||
logger.error("Get your API key from Uptime Kuma: Settings → API Keys")
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Initialize ESP32 controller
|
# Initialize ESP32 controller
|
||||||
esp = ESP32Controller(ESP_IP, ESP_API_KEY)
|
esp = ESP32Controller(ESP_IP, ESP_API_KEY)
|
||||||
|
|
||||||
|
# Initialize ESP32 controller
|
||||||
|
esp = ESP32Controller(ESP_IP, ESP_API_KEY)
|
||||||
# Connect to ESP32
|
# Connect to ESP32
|
||||||
logger.info(f"Connecting to ESP32 at {ESP_IP}...")
|
logger.info(f"Connecting to ESP32 at {ESP_IP}...")
|
||||||
if not await esp.connect():
|
if not await esp.connect():
|
||||||
@@ -300,6 +348,14 @@ async def main():
|
|||||||
|
|
||||||
logger.info(f"Starting monitoring loop (interval: {POLL_INTERVAL}s)")
|
logger.info(f"Starting monitoring loop (interval: {POLL_INTERVAL}s)")
|
||||||
|
|
||||||
|
# Start Kuma push monitor if configured
|
||||||
|
push_task = None
|
||||||
|
if KUMA_PUSH_URL:
|
||||||
|
push_task = asyncio.create_task(kuma_push_monitor(KUMA_PUSH_URL, KUMA_PUSH_INTERVAL))
|
||||||
|
logger.info(f"Kuma push monitor started (URL: {KUMA_PUSH_URL}, Interval: {KUMA_PUSH_INTERVAL}s)")
|
||||||
|
else:
|
||||||
|
logger.info("Kuma push monitor not configured")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
# Wait for esp to be fully connected
|
# Wait for esp to be fully connected
|
||||||
@@ -327,6 +383,13 @@ async def main():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Unexpected error: {e}")
|
logger.error(f"Unexpected error: {e}")
|
||||||
finally:
|
finally:
|
||||||
|
# Cancel push monitor task if running
|
||||||
|
if push_task and not push_task.done():
|
||||||
|
push_task.cancel()
|
||||||
|
try:
|
||||||
|
await push_task
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
await esp.disconnect()
|
await esp.disconnect()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user