CreaRack-SL

Provisioning de MonitoringTargets sale del GET — reconciliación en Huey (sa6-G1, v1.89.0)

Para qué sirve

Cuando alguien abre Observatory, Wireless, UPS o Signage, la página deja de reparar por su cuenta los sensores de monitorización que faltan o están mal — antes lo hacía en el instante mismo de cargar, ahora solo detecta que algo falta y avisa a un trabajador de fondo (worker) para que lo arregle fuera del navegador. Nadie nota diferencia salvo un detalle: si acabas de dar de alta un dispositivo, el sensor nuevo no aparece en la MISMA carga que lo detectó, sino en la siguiente (segundos después).

Por qué — el problema que resuelve

Las 4 vistas (observatory_view, wireless_view, ups_view, signage_view en monitoring/views.py) creaban y reparaban MonitoringTarget — el sensor que sondea un equipo — DENTRO del render: bulk_create + bulk_update + aviso al Agente en cada carga de página. Un GET que escribe es frágil (el navegador lo repite por prefetch, un refresco a medio camino deja trabajo a medias) y mete esas escrituras en la latencia de la propia página. Es el hallazgo sa6-G1 de la Auditoría Suprema, y cumple el “próximo paso” que ya había quedado anotado en [[decision—20260604—broken-access-control-vistas-observatory]] tras cerrar el hueco de permisos de esas mismas vistas.

Cómo funciona ahora

monitoring/services/provisioning.py separa detección de aplicación:

  • Solo lectura (corre en el request): profile_targets_need_provision(profiles) y device_targets_need_provision(org, devices) — devuelven True/False, sin tocar la base de datos.
  • Escritura (corre en el worker): provision_profile_targets(org, profiles), la nueva provision_device_targets(org) y repair_stale_down_targets(org) — esta última corrige el estado “down” cuando en realidad nunca se llegó a medir latencia (pasa a “unknown”).

Ambos caminos comparten el mismo planificador, _plan_device_targets, así que lo que la vista detecta y lo que el worker aplica no pueden divergir.

Cuando una vista detecta desajuste, encola monitoring.tasks.reconcile_org_targets(org_id) — una task de Huey sin AsyncJob ni polling (a diferencia de Auto-Plan o la subida de MIBs, ver [[feature—network—mib-upload-async]]): es fire-and-forget, no hay job_id que el cliente pueda consultar. La task reconcilia la organización ENTERA (las fichas de las 3 páginas + los Device de rack con gestión de red + el “down” sin medir), no solo la página que la disparó, y es idempotente a propósito — no lleva lock_task porque dos pasadas simultáneas son inocuas (bulk_create con ignore_conflicts) y un lock global descartaría la segunda pasada en vez de dejarla encolada.

Límite honesto

Un target recién provisionado no aparece en la misma carga que lo disparó — sale en la siguiente, unos segundos después. Antes el render lo creaba y lo pintaba de una sola pasada.

Tests

tests/monitoring/test_targets_reconcile_async.py (nuevo, 249 líneas): el GET no escribe en las 4 páginas, solo encola cuando hay desajuste real, un usuario de solo lectura no dispara el encolado, y la task provisiona/reactiva/repara de forma idempotente.

Commits relacionados

  • 17df12e7 (2026-08-31) — PR #475, v1.89.0: refactor(monitoring+network) T2 síncrono a Huey.

Véase también

  • [[concept—general—que-operaciones-sincronas-se-ejecutan-en-el-reques]]
  • [[decision—20260604—broken-access-control-vistas-observatory]]
  • [[entity—monitoring—service—target-lifecycle]]
  • [[feature—blueprints—autoplan-async]]
  • [[feature—network—mib-upload-async]]