Files
fn_registry/python/functions/infra/discover_local_services.md
T
egutierrez 32c7336bf6 feat(infra): auto-commit con 56 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-21 14:22:55 +02:00

4.7 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
discover_local_services function py infra 1.1.0 impure discover_local_services(manifest_path: str, include_registry: bool = True) -> list[dict] Descubre los servicios locales del sistema local_hub expuestos como subdominios *.localhost. Lee el manifiesto YAML, normaliza la metadata de cada servicio, opcionalmente añade los servicios del registry con puerto via fn doctor, y comprueba up/down por chequeo de puerto TCP en 127.0.0.1. Robusta: no lanza por servicio caido (up=False) ni por fallo de fn doctor.
local-hub
infra
services
discovery
caddy
glance
python
false error_go_core
json
os
socket
subprocess
sys
yaml
name desc
manifest_path ruta al manifiesto YAML de servicios (apps/local_hub/local_services.yaml) con claves dashboard_subdomain, glance_port y services[]
name desc
include_registry si True, añade los servicios del registry con port>0 que no esten ya en el manifiesto (dedup por port y por subdomain), obtenidos de fn doctor services-spec --json
lista de dicts normalizados, cada uno con las claves name, subdomain, port, health_path, title, icon, category, rewrite_host (bool, passthrough del manifiesto; False para servicios del registry; lo consume render_caddyfile para reescribir el header Host), up (bool de estado vivo por puerto TCP) true
test_golden_service_up_with_all_keys
test_edge_closed_port_is_down
test_defaults_derived_for_missing_fields
test_empty_manifest_returns_empty_list
test_rewrite_host_passthrough_desde_manifiesto
python/functions/infra/discover_local_services_test.py python/functions/infra/discover_local_services.py

Ejemplo

from discover_local_services import discover_local_services

# Solo manifiesto (sin tocar el registry):
servicios = discover_local_services(
    "apps/local_hub/local_services.yaml",
    include_registry=False,
)
for s in servicios:
    estado = "UP" if s["up"] else "DOWN"
    print(f'{s["title"]:<16} {s["subdomain"]}.localhost -> :{s["port"]}  [{estado}]')

# Manifiesto + servicios del registry con puerto:
todos = discover_local_services("apps/local_hub/local_services.yaml")
print(len([s for s in todos if s["up"]]), "servicios vivos")

Como script (imprime JSON a stdout):

python/.venv/bin/python3 python/functions/infra/discover_local_services.py apps/local_hub/local_services.yaml

Cuando usarla

Úsala como fase de descubrimiento del sistema local_hub antes de renderizar el Caddyfile o la config de Glance: cuando necesites la lista normalizada de servicios locales (*.localhost) con su estado up/down resuelto. También cuando quieras un inventario unificado de servicios manuales (contenedores, daemons de terceros) más los servicios del registry con puerto, deduplicados.

Gotchas

  • up se decide por conexión TCP a 127.0.0.1:<port> con timeout 0.5s, NO por GET HTTP. Un servicio puede aceptar la conexión y devolver 404/500 en / y aun así marcar up=True. Es intencional: solo valida que el puerto esté escuchando.
  • Solo comprueba 127.0.0.1 (loopback). Servicios que bindean únicamente a otra interfaz se reportan como down.
  • include_registry=True ejecuta fn doctor services-spec --json (fallback a services --json) como subproceso desde la raíz del repo. Si fn no está, falla, tarda más de 20s o devuelve JSON inválido, la función no lanza: sigue solo con el manifiesto. Por eso el resultado puede variar según el entorno.
  • La raíz del repo se resuelve por FN_REGISTRY_ROOT o subiendo directorios hasta encontrar registry.db. Si no la encuentra, usa el cwd.
  • El dedup del registry es por port Y por subdomain: un servicio del registry cuyo puerto o subdominio derivado ya esté en el manifiesto se omite.
  • El subdominio de un servicio del registry se deriva por una tabla de alias (dag_engine->dag, registry_api->registry, sqlite_api->sqlite, osint_db->osint, ...) y, para el resto, el primer token antes de _.
  • Lanza RuntimeError solo si el manifiesto no se puede leer o parsear (path inexistente, YAML inválido). Eso sí es un error duro.
  • La clave rewrite_host es passthrough del manifiesto (default False); para los servicios añadidos desde el registry siempre es False. La consume render_caddyfile para emitir header_up Host en el bloque del servicio.

Capability growth log

  • v1.1.0 (2026-06-20) — añade clave rewrite_host (passthrough del manifiesto) para que render_caddyfile reescriba el Host