Ir al contenido

Blog ·

Una barra de progreso que se niega a adivinar

Casi todas las estimaciones de tiempo son inventadas. Esta es la regla que decide cuándo el panel puede mostrar una, y qué dice en pantalla cuando no puede.

Por Provibr

Alguien pulsa instalar. Hay que clonar una máquina, arrancarla, configurarla y comprobarla, y en algún punto de todo eso el cliente quiere saber una sola cosa: cuánto va a tardar.

La respuesta fácil es una cuenta atrás. Se elige un número plausible, se resta un segundo cada segundo, y la pantalla parece saber algo. No lo sabe. Una cuenta atrás es una promesa sobre un momento, y nadie en la casa conoce ese momento.

Así que la regla se puso por escrito, se le dio un número de versión y se hizo que el panel diga en voz alta cuándo no cumple los requisitos.

La regla, en resumen

Una estimación de tiempo aparece solo cuando se cumplen dos condiciones a la vez. Tiene que haber al menos veinte ejecuciones correctas del mismo tipo de trabajo en los últimos treinta días, y la dispersión tiene que ser estrecha: el percentil noventa no puede superar a la mediana en más de dos veces y media. Si falla cualquiera de las dos, la pantalla muestra la etapa, el tiempo transcurrido y una frase que dice que no hay estimación.

Esos tres números viven en una única constante con un campo de versión al lado, y ninguna otra parte del código tiene permiso para opinar sobre ellos.

SituaciónQué muestra la pantalla
Menos de veinte ejecuciones comparables en treinta días«No reliable time estimate yet» (todavía no hay una estimación de tiempo fiable), con cuántas ejecuciones se han registrado y cuántas hacen falta
Veinte o más en treinta días, pero la dispersión es demasiado amplia«No reliable time estimate», y que las ejecuciones estaban demasiado separadas entre sí
Ambas condiciones cumplidas«Comparable tasks took X to Y minutes, based on N runs in the last 30 days» (tareas comparables tardaron de X a Y minutos, según N ejecuciones en los últimos 30 días)

Conviene leer la tercera fila con atención. Es un intervalo, y nombra su propia evidencia. No es una barra que repta hacia una meta, y nunca se convierte en «quedan 3 minutos».

Por qué un intervalo y no una cuenta atrás

Una cuenta atrás acumula dos errores. Oculta la incertidumbre y se reafirma cada segundo, así que la equivocación tiene ritmo. Todo el mundo ha visto un diálogo de copia prometer cuatro minutos, luego catorce, luego dos, y ha aprendido en unos treinta segundos que el número no significa nada. Una vez que un lector aprende eso, cualquier otro número de la pantalla vale un poco menos. Un intervalo, enunciado una sola vez y con su recuento de muestras al lado, no puede hacer eso.

La condición de dispersión es la parte que hace el trabajo de verdad. Veinte muestras con una mediana de cuatro minutos y un percentil noventa de cuarenta minutos no son una cohorte con una predicción dentro; son dos poblaciones distintas bajo una misma etiqueta, y promediarlas produce una cifra con decimales y sin significado. Dos y medio es un número elegido, no derivado, y el campo de versión existe para que cambiarlo más adelante sea una decisión visible.

La cohorte es la cuenta propia, y es deliberado

La forma obvia de llegar rápido a veinte muestras es medir en toda la plataforma. No se hace. La cohorte es el tipo de trabajo dentro de una sola organización.

Hay dos razones, y la segunda es la que lo decidió.

La primera es la comparabilidad. El historial propio es la población más parecida que existe: el mismo hipervisor, la misma red, las mismas imágenes, el mismo almacenamiento.

La segunda es que el recuento de muestras está en la pantalla. Una frase que dice cuántas ejecuciones comparables ha visto la plataforma en treinta días es una afirmación sobre nuestro propio volumen, impresa en el panel de un cliente, y se entregaría a cambio de una estimación ligeramente mejor. Acotar la consulta a una organización significa que el número que sale en pantalla es un hecho sobre quien lo lee.

La consecuencia práctica es que una cuenta joven no ve ninguna estimación durante un tiempo, y ese es el comportamiento correcto y no un hueco que haya que rellenar. No mostrar nada es mejor que mostrar un número que no significa nada.

No hay tabla de muestras

La duración de una tarea correcta es la diferencia entre dos marcas de tiempo que ya están guardadas en la propia tarea. No hay una tabla aparte de mediciones.

Eso suena a un ahorro evidente, y merece la pena decir por qué fue una decisión. Una segunda tabla guardaría la misma verdad dos veces, y las dos divergirían la primera vez que un barrido de retención tocase una y no la otra. Lo único que añadiría de verdad son muestras que sobreviven a las tareas de las que salieron, y eso solo importa cuando el periodo de retención es más corto que la ventana de medición. Hoy la retención es de noventa días y la ventana es de treinta, así que la pregunta no llega a plantearse.

Una nota al pie que ya ha mordido a este código antes: la consulta de percentil devuelve un double y la de recuento devuelve un bigint, que el controlador entrega como cadena. Las dos necesitan conversión, y olvidar exactamente una de las dos falla en silencio en lugar de fallar a gritos.

Etapas, porque un porcentaje tiene que salir de algún sitio

Cada tipo de tarea lleva una lista ordenada de etapas. Una instalación pasa por en cola, preparando, arrancando, instalando y terminando. Una descarga desde una URL pasa por en cola, enviada al agente, descargando, verificando y aplicando. El porcentaje se deriva de la posición en esa lista, salvo que el trabajo subyacente informe de un porcentaje real propio, en cuyo caso gana ese.

Esa anulación importa más de lo que parece. Una instalación informa de su propia cifra de progreso y esa cifra se muestra en la página de ese mismo servidor; si el cajón calculase un segundo número a partir de las posiciones de las etapas, una misma pantalla llevaría dos porcentajes distintos sobre el mismo trabajo. Eso es una segunda copia de la verdad, una capa más arriba.

La traducción de fases de instalación a etapas está en un único sitio, escrita como un registro exhaustivo y no como una sentencia switch. Catorce fases repartidas en dos escaleras de instalación distintas se corresponden con cinco etapas que un cliente reconocería. Una fase nueva es un error de compilación, no una etapa que se cuela sin ruido hasta la primera.

Obsoleto no es fallido

Hay dos umbrales sobre lo reciente que es el último informe de progreso: dos minutos y diez minutos. Pasado el primero, la pantalla dice que no ha habido ninguna actualización desde una hora concreta. Pasado el segundo, dice que no se ha informado de nada desde entonces.

Ninguno de los dos cambia el estado. El trabajo puede estar ejecutándose perfectamente. Lo que se ha parado es el envío de informes, y un lector merece que se lo digan en lugar de mirar una barra que no se mueve y sacar sus propias conclusiones. Confundir el silencio con el fallo es el mismo error que cerrar un incidente porque dejaron de llegar las mediciones, y merece la pena mantener las dos palabras separadas en todos los sitios donde aparecen.

El cajón no es dueño de nada

El cajón de tareas en segundo plano de la cabecera se apoya en todo lo anterior, y su regla de diseño es corta: no guarda ningún estado propio sobre el trabajo. La única pieza de estado local de ese componente es si el panel está abierto. No hay bucle de consulta, ni intervalo, ni un segundo socket. El estado inicial llega de la misma consulta que usa la página de detalle, y las actualizaciones en vivo llegan por el almacén compartido de tiempo real.

Una prueba lee el árbol sintáctico del componente y falla si alguna variable de estado local llega a contener un estado, una etapa o un porcentaje. Esa es una garantía más fuerte que una revisión de código, por la misma razón por la que un comentario no es una prueba.

Hay ahí dentro un detalle fácil de invertir: los grupos del cajón se calculan después de aplicar el parche en vivo, no antes. Calcularlos primero deja una tarea que acaba de fallar sentada en el grupo de las que se ejecutan hasta la siguiente carga completa de la página, mostrando sin ruido un indicador de actividad junto a algo que ya está en rojo.

Tres defectos que solo encontró la verificación

Los tres compilaban, pasaban la comprobación de tipos y pasaban las pruebas unitarias.

El comprobante no se escribía en ninguna parte. El código llamaba a una función que no existía, así que una instalación correcta producía una tarea con una sección de resultado que se quedaba vacía para siempre.

Una fase de instalación no reconocida borraba la etapa registrada y la dejaba vacía. La correspondencia devuelve correctamente nada para una fase que no conoce, pero quien la llamaba escribía esa nada en la fila, así que un agente antiguo que informase de una fase renombrada habría borrado la etapa de una tarea que iba perfectamente. La corrección es un único valor de reserva, la etapa que ya estaba ahí, y la protección se demostró en rojo antes de darla por buena.

Una tarea terminada seguía girando. La etapa de una tarea completada sigue siendo la última que alcanzó, lo cual es correcto, porque de otro modo no se podría ver dónde acabó. El fallo estaba en preguntar «¿es esta etapa la actual?» comparando nombres, cuando la pregunta real es si la tarea sigue activa. Una tarea fallida tampoco recibe una marca verde en la etapa en la que murió: esa etapa se abandonó en lugar de completarse, así que tiene un estado propio en vez de archivarse como hecha o como no iniciada, dos cosas que afirmarían algo falso.

Lo que dejaríamos por escrito

  1. Poner la regla de estimación en una única constante versionada. La pregunta «¿era defendible la estimación que se mostró en marzo?» solo tiene respuesta si se sabe qué regla estaba en vigor.
  2. Convertir la ausencia de estimación en una frase, no en un espacio vacío. Un hueco donde debería haber un número se lee como un error; «No reliable time estimate yet. 6 of 20 comparable runs recorded.» (todavía no hay una estimación de tiempo fiable, 6 de 20 ejecuciones comparables registradas) se lee como un sistema que sabe lo que no sabe.
  3. Acotar la cohorte al cliente, y aceptar que las cuentas nuevas no vean nada durante un tiempo. La alternativa imprime el volumen propio en la pantalla ajena.
  4. No dejar nunca que un cajón, una insignia o un widget guarde su propia copia de un estado. Dos números sobre un mismo trabajo en una misma pantalla es peor que ningún número.
  5. Separar el silencio del fallo en el vocabulario, en el modelo de datos y en la pantalla, y mantenerlos separados en todas partes.

Los límites honestos: esta capa funciona hoy para cuatro tipos de trabajo, y la lista es corta a propósito porque un tipo que nadie puede iniciar es una categoría que se muestra vacía. El flujo de cancelación puede registrar una petición, pero todavía no hay ninguna capa de ejecución que confirme ninguna, y el cajón no tiene punto de entrada por debajo de 768 píxeles de ancho de pantalla.

El mismo argumento, aplicado a aquello a lo que suele ir enganchada una barra de progreso, está en por qué un 200 de Proxmox no es un resultado, y la razón por la que dejamos de fiarnos de nuestros propios plazos está en un tiempo de espera no es un botón de parada.

Del trabajo de plataforma en Provibr.

Empiece con un host y un agente

Cree una cuenta, instale el agente con un solo comando y conecte su primer host de Proxmox. El periodo de prueba dura 14 días y no pide ningún dato de pago.