Pasar a espacios de trabajo más grandes sin hacer esperar a nadie
Cada proyecto de Mythex tiene su propio espacio de trabajo: un pequeño ordenador en la nube donde el agente escribe código y se ejecuta la vista previa de tu app. Habíamos subido los espacios de trabajo nuevos de 1 GB de memoria a 2 GB, pero los antiguos se quedaron en 1 GB: el día que lo comprobamos, alrededor de una cuarta parte. Nuestra primera solución movía un proyecto a un espacio de trabajo más grande la próxima vez que se abría. En su primer día en producción, eso hizo esperar siete minutos a una persona. Pusimos un límite de tiempo estricto y, después, quitamos el traslado de la apertura de proyectos por completo.
Por qué los espacios antiguos seguían pequeños
Nuestro proveedor de entornos fija el tamaño de un espacio de trabajo al crearlo, y lo mantiene a lo largo de cada pausa y reanudación. Cambiar la plantilla —la receta con la que se construyen los espacios nuevos— solo afecta a los espacios creados después del cambio. Nada redimensiona los que ya existen.
Eso importaba. Uno de los espacios pequeños se quedó sin memoria durante un git push mientras arrancaba su vista previa, y dejó de responder durante 11 minutos. Una publicación falló por ello.
Primer intento: mover el proyecto al despertar
Los espacios de trabajo se pausan cuando nadie los usa y se despiertan al abrir el proyecto. Despertar parecía el momento adecuado para mover un proyecto, porque nadie está trabajando en él todavía.
El traslado funcionaba así:
- Comprobar el tamaño. Si el espacio de trabajo es menor de 2 GB, se mueve. Si su tamaño es desconocido, no se hace nada.
- No molestar a una publicación. Una publicación lee los archivos del espacio de trabajo, así que si hay una en curso, se omite el traslado.
- Empaquetar el proyecto. Se archiva todo lo del proyecto —incluido su historial de git, es decir, todos los puntos de control que tiene el proyecto, y el archivo
.envde la app, que pertenece al propietario—, pero se dejan fuera las dependencias instaladas (node_modules), que pueden reinstalarse. - Copiar directamente. Se transmite el archivo desde el espacio antiguo a uno nuevo de 2 GB, de modo que nunca tiene que caber en la memoria de nuestro propio servidor.
- Comparar antes de cambiar. En ambos espacios se cuentan los archivos, se lee el último punto de control y se cuentan los puntos de control. Solo se cambia si las tres cosas coinciden.
- Conservar el antiguo ante cualquier fallo. Cualquier error o cualquier discrepancia descarta el espacio nuevo y abre el proyecto en el antiguo, como antes.
Un detalle de la comparación importaba más de lo que parece. La comprobación se ejecuta con la cuenta de administrador, y git se niega a leer un repositorio que pertenece a otro usuario. No imprimía nada en ninguno de los dos lados, y "nada" coincidía con "nada", así que la comprobación pasaba sin comparar ningún historial. Le dijimos a git que confiara en el directorio y añadimos una prueba para que eso no se vuelva a colar.
Lo que salió mal el primer día
El primer día en producción, al empaquetar un proyecto se alcanzó un tiempo límite de cinco minutos para un comando, dentro del despertar. El propietario esperó siete minutos a que se abriera su espacio de trabajo. Y como el traslado había fallado, el proyecto seguía siendo pequeño, así que la siguiente apertura lo volvería a intentar y les haría esperar otra vez.
Una migración que obliga a alguien a esperar al abrir su propio proyecto es un mal negocio. Toda la idea de hacerlo al despertar era que nadie lo notara.
Segundo intento: un presupuesto estricto
Ese mismo día cambiamos cuatro cosas:
- Un minuto para todo el traslado. Cada paso —comprobar el tamaño, empaquetar, crear el espacio nuevo, copiar, desempaquetar, comparar— comparte un único presupuesto de 60 segundos. Cuando se agota, el proyecto se abre en el espacio antiguo.
- Detener el trabajo, no solo la espera. Rendirse de nuestro lado no basta si el archivado sigue ejecutándose dentro del espacio de trabajo que el propietario está a punto de usar. Cada comando de archivado ahora se mata dentro del propio espacio de trabajo poco antes de que termine el presupuesto. Si el espacio nuevo llega después de que nos hayamos rendido, se descarta.
- No hacer esperar al propietario por la limpieza. Borrar el archivo temporal de archivado ahora se hace en segundo plano.
- No reintentar en cada apertura. Un proyecto que no pudo moverse se deja en paz durante 24 horas, de modo que un fallo cueste como máximo un retraso al día, y no uno por cada apertura.
Tercer intento: sacarlo del despertar
Con eso, el peor caso pasó a durar un minuto. Pero un minuto sigue siendo un minuto, y nos dimos cuenta de que el traslado no necesitaba estar en el camino de nadie.
Ningún espacio de trabajo se crea ya a 1 GB. Así que esto no es un proceso continuo; es un trabajo de una sola vez con una lista fija de espacios de trabajo. Hacerlo dentro del despertar significaba que una persona real pagaba cada traslado lento, y la única forma de saber que un espacio no iba a moverse era que alguien acabara de esperarlo.
Así que quitamos el traslado del despertar por completo. Abrir un proyecto hace lo mismo que antes. Los espacios pequeños restantes se gestionan como un lote supervisado: nadie espera por ello, y un espacio que no se puede mover aparece en el informe del lote, donde podemos revisarlo, en lugar de aparecer delante de la persona que es propietaria del espacio.
Lo que aprendimos
- Redimensionar no siempre es posible. Cuando una plataforma fija un tamaño al crear, subir el valor predeterminado solo ayuda a lo nuevo. Planifica para lo antiguo.
- "Todavía nadie la usa" sigue significando que alguien espera. El trabajo que se hace al entrar en un producto es trabajo que una persona observa.
- Pon un presupuesto a todo lo que esté en el camino de un usuario, y detén el trabajo cuando se agote. Agotar el tiempo de nuestro lado mientras un comando sigue ejecutándose en otro sitio solo traslada el problema.
- Una migración de una sola vez pertenece a un trabajo de una sola vez. Esconderla dentro de las acciones cotidianas la hace más barata de escribir y más cara de ejecutar.
- Prueba tus comprobaciones de seguridad. Una comparación que no compara nada se ve exactamente igual que una que pasó.
Si construyes en Mythex, no tienes que hacer nada: el objetivo es simplemente que se queden sin memoria menos espacios de trabajo, y que abrir un proyecto siga siendo igual de rápido. Cómo se pausan y se despiertan los espacios de trabajo está explicado en la documentación, en espacio de trabajo privado. Para otra historia de falta de memoria, consulta el fallo por falta de memoria escondido en una etiqueta de progreso.