Make service health-check self-diagnosing
When a service group's cog stays disabled the log now says WHY: _service_health returns the actual connection error (ConnectionError = refused/down, ConnectTimeout = firewall/slow, gaierror = DNS/wrong host) instead of a bare 'unreachable', and on_ready logs the resolved FILE/LIBRARIAN/RADIO addresses so an env-var that never reached the process (address falls back to the 192.168.1.15:5000 default) is obvious at a glance. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit was merged in pull request #9.
This commit is contained in:
@@ -120,13 +120,15 @@ SERVICE_EXTENSION_GROUPS = {
|
||||
SERVICE_RECHECK_SECONDS = 300
|
||||
|
||||
|
||||
def _service_alive(url: str) -> bool:
|
||||
"""True when the service answers HTTP at all (any status code counts)."""
|
||||
def _service_health(url: str):
|
||||
"""Return None when the service answers HTTP at all (any status counts),
|
||||
otherwise the connection error explaining WHY it's unreachable (refused vs
|
||||
timeout vs DNS - the difference points straight at the cause)."""
|
||||
try:
|
||||
requests.get(url, timeout=3)
|
||||
return True
|
||||
except requests.exceptions.RequestException:
|
||||
return False
|
||||
return None
|
||||
except requests.exceptions.RequestException as exc:
|
||||
return exc
|
||||
|
||||
|
||||
async def _load_extension_safe(name: str) -> bool:
|
||||
@@ -152,12 +154,14 @@ async def _load_service_groups() -> bool:
|
||||
missing = [e for e in group["extensions"] if e not in client.extensions]
|
||||
if not missing:
|
||||
continue
|
||||
alive = await asyncio.to_thread(_service_alive, group["health_url"])
|
||||
if not alive:
|
||||
err = await asyncio.to_thread(_service_health, group["health_url"])
|
||||
if err is not None:
|
||||
logger.warning(
|
||||
"Service '%s' unreachable (%s) - cogs stay disabled: %s",
|
||||
"Service '%s' unreachable (%s) [%s: %s] - cogs stay disabled: %s",
|
||||
service,
|
||||
group["health_url"],
|
||||
type(err).__name__,
|
||||
err,
|
||||
", ".join(missing),
|
||||
)
|
||||
continue
|
||||
@@ -204,6 +208,16 @@ async def on_ready():
|
||||
for extension in CORE_EXTENSIONS:
|
||||
await _load_extension_safe(extension)
|
||||
|
||||
# Log the ACTUALLY-resolved service addresses. When one shows the built-in
|
||||
# default (192.168.1.15:5000) it means the matching CONJURER_* env var never
|
||||
# reached the process - the single most common cause of "service unreachable"
|
||||
# confusion. Printing them makes env-vs-default obvious at a glance.
|
||||
logger.info(
|
||||
"Resolved service addresses -> musician(file): %s | librarian: %s | radio: %s",
|
||||
FILE_SERVICE_ADDRESS,
|
||||
LIBRARIAN_SERVICE_ADDRESS,
|
||||
RADIO_SERVICE_ADDRESS,
|
||||
)
|
||||
await _load_service_groups()
|
||||
logger.info("Sensors: online")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user