fix: cache external ip and align domain health checks

Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/01540c60-35d3-481a-8558-945a81d86976

Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-04-15 01:31:47 +00:00
committed by GitHub
parent 04587efad3
commit f24c9c45b2

View File

@@ -53,6 +53,7 @@ REBUILD_UNIT = "sovran-hub-rebuild.service"
# to api_updates_status() so that the full log is returned to the frontend # to api_updates_status() so that the full log is returned to the frontend
# even when the frontend's offset is pointing past the pre-restart content. # even when the frontend's offset is pointing past the pre-restart content.
_update_recovery_happened: bool = False _update_recovery_happened: bool = False
_cached_external_ip: str = "unavailable"
BACKUP_LOG = "/var/log/sovran-hub-backup.log" BACKUP_LOG = "/var/log/sovran-hub-backup.log"
BACKUP_STATUS = "/var/log/sovran-hub-backup.status" BACKUP_STATUS = "/var/log/sovran-hub-backup.status"
@@ -2185,6 +2186,17 @@ async def api_services():
if needs_domain: if needs_domain:
if not domain: if not domain:
has_domain_issues = True has_domain_issues = True
else:
try:
results = socket.getaddrinfo(domain, None)
if not results:
has_domain_issues = True
else:
resolved_ip = results[0][4][0]
if _cached_external_ip != "unavailable" and resolved_ip != _cached_external_ip:
has_domain_issues = True
except (socket.gaierror, Exception):
has_domain_issues = True
health = "needs_attention" if (has_port_issues or has_domain_issues) else "healthy" health = "needs_attention" if (has_port_issues or has_domain_issues) else "healthy"
# Check Bitcoin IBD state # Check Bitcoin IBD state
if unit == "bitcoind.service" and enabled: if unit == "bitcoind.service" and enabled:
@@ -2331,10 +2343,8 @@ async def api_service_detail(unit: str, icon: str | None = None):
domain = None domain = None
# IPs # IPs
internal_ip, external_ip = await asyncio.gather( internal_ip = await loop.run_in_executor(None, _get_internal_ip)
loop.run_in_executor(None, _get_internal_ip), external_ip = _cached_external_ip
loop.run_in_executor(None, _get_external_ip),
)
_save_internal_ip(internal_ip) _save_internal_ip(internal_ip)
# Domain status check # Domain status check
@@ -2512,6 +2522,7 @@ async def api_service_detail(unit: str, icon: str | None = None):
@app.get("/api/network") @app.get("/api/network")
async def api_network(): async def api_network():
global _cached_external_ip
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
internal, external = await asyncio.gather( internal, external = await asyncio.gather(
loop.run_in_executor(None, _get_internal_ip), loop.run_in_executor(None, _get_internal_ip),
@@ -2519,6 +2530,7 @@ async def api_network():
) )
# Keep the internal-ip file in sync for credential lookups # Keep the internal-ip file in sync for credential lookups
_save_internal_ip(internal) _save_internal_ip(internal)
_cached_external_ip = external
return {"internal_ip": internal, "external_ip": external} return {"internal_ip": internal, "external_ip": external}
@@ -3260,7 +3272,7 @@ class DomainCheckRequest(BaseModel):
async def api_domains_check(req: DomainCheckRequest): async def api_domains_check(req: DomainCheckRequest):
"""Check DNS resolution for each domain and verify it points to this server.""" """Check DNS resolution for each domain and verify it points to this server."""
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
external_ip = await loop.run_in_executor(None, _get_external_ip) external_ip = _cached_external_ip
def check_domain(domain: str) -> dict: def check_domain(domain: str) -> dict:
try: try: