La tarea de limpieza que habría borrado tu avatar

Product

Los espacios de trabajo tienen avatar desde la v0.4.0. La función es pequeña: subes una imagen y aparece en el selector de espacios de trabajo. La subida funcionó a la primera. La imagen apareció en todos los sitios donde debía. Todos los tests pasaron.

También habría desaparecido tres días después.

Dos formas de perder un archivo

En Notez, los archivos subidos van al almacenamiento de objetos antes de que nada en la base de datos apunte a ellos. Es deliberado: el navegador envía los bytes directamente a S3 con un POST prefirmado, así que una subida grande nunca ocupa la API. Primero se escribe la fila que describe el archivo y después llegan los bytes.

Ese orden deja un hueco. Si alguien elige un archivo y cierra la pestaña, los bytes pueden llegar sin que nada los referencie nunca. El almacenamiento se llena de objetos que ninguna nota, ningún avatar y ningún usuario volverá a pedir.

Por eso hay una tarea en segundo plano. Una vez al día busca archivos que se subieron pero nunca se adjuntaron a nada, y borra los que tienen más de tres días. La palabra clave ahí es adjunto: un booleano que el proceso de subida no marca. Terminar una subida marca el archivo como subido. Otra cosa tiene que reclamarlo.

En los avatares de usuario, esa otra cosa es la actualización del perfil. Cuando pones una imagen nueva, el código hace dos cosas además de escribir la URL en tu cuenta: marca el archivo nuevo como adjunto y pone el archivo anterior en la cola de borrado. Las dos mitades importan. Sin la primera, la tarea de limpieza se lleva una imagen que está en uso. Sin la segunda, todos los avatares que hayas puesto alguna vez se quedan para siempre en el almacenamiento y cuentan para tu cuota.

Los avatares de los espacios de trabajo no hacían ninguna de las dos. La URL se escribía en el espacio de trabajo, la imagen se mostraba y el archivo se quedaba ahí marcado como subido, sin adjuntar, a tres días de ser borrado.

Por qué nada lo detectó

Los tests pasaban porque probaban lo que construí. La subida devuelve una URL, la URL se guarda, el componente la muestra: todo cierto, y todo seguía siendo cierto con el fallo presente. Nada comprobaba un booleano en otra tabla, porque no se me había ocurrido que un booleano en otra tabla formara parte de la función.

Además, el fallo es invisible en el momento. No hay error, ni aviso en la consola, ni una petición que falle. Entre el fallo y su síntoma pasan tres días y una ejecución del cron, y el síntoma es una imagen rota en la pantalla de otra persona.

Lo que lo sacó a la luz fue leer el código del avatar de usuario antes de dar por hecho que el mío era equivalente. Ese flujo tenía dos pasos que el mío no tenía, y los comentarios explicaban exactamente por qué. Ese es el argumento para dejar en el código el porqué y no solo el mecanismo: quien copie el patrón después necesita saber qué piezas sostienen todo lo demás.

Borrar también es editar

Al arreglar el reemplazo apareció un tercer caso. Cuando se elimina un espacio de trabajo, su avatar está adjunto, así que la tarea de limpieza, que solo se lleva archivos sin adjuntar, nunca lo tocará. Ya nada apunta al archivo y nada lo hará nunca. Queda huérfano justo de la única forma que la tarea de limpieza no puede arreglar.

Ahora, al eliminar un espacio de trabajo, se libera también su icono.

El patrón general: si una tarea en segundo plano decide qué conservar preguntando si algo sigue haciendo referencia a un archivo, entonces cada ruta del código que deja de referenciarlo tiene que decirlo. Reemplazar. Quitar. Eliminar el elemento padre. Si se te escapa una, tienes una fuga; si una va al revés, pierdes datos. Desde fuera no se parecen en nada, y salen de la misma línea que falta.

Qué cambié

  • Poner un avatar a un espacio de trabajo marca el archivo como adjunto, así que la tarea de limpieza no lo toca.

  • Reemplazarlo pone en cola el archivo antiguo para borrarlo, con el mismo plazo de 30 días para restaurarlo que cualquier otra cosa que elimines.

  • Eliminar un espacio de trabajo libera su avatar en lugar de dejarlo abandonado.

Ahora siete tests cubren el ciclo de vida, incluidos los casos en los que no debe pasar nada: renombrar un espacio de trabajo no debe poner su avatar en cola para borrarlo, y volver a guardar la misma URL no es un reemplazo. Comprobé que fallan sin la corrección antes de fiarme de ellos.

Sigue leyendo