ecosystem-wikicómo extender los templates sin romper sus convenciones
‹ todas las recipes

Cuando el fichero ya no cabe en la petición

template-api
último cambio 2026-09-25

Entregar un fichero que se genera al pedirlo funciona mientras el paquete sea pequeño: se construye sobre la respuesta y no se guarda nada. Esa entrada dejó escrito cuándo deja de valer — “si el paquete deja de ser pequeño o aparecen timeouts”—, y este es ese caso.

Si el fichero no se puede construir dentro del tiempo de una petición, o tiene que seguir existiendo mañana, deja de ser una respuesta y pasa a ser un objeto con estado.

Dos cosas cambian a la vez, y conviene no confundirlas: el tamaño obliga a construirlo fuera de la petición; la disponibilidad obliga a guardarlo. Si solo pasara lo primero, bastaría con construirlo y servirlo una vez.

La máquina de estados

Una fila por petición: PENDING → RUNNING → READY, o FAILED, y EXPIRED cuando caduca. La petición del usuario solo crea la fila y devuelve su id; el trabajo lo hace una tarea programada que recoge las pendientes.

Tres detalles que se pagan caros si faltan:

No hace falta una cola para esto. Una cola aporta reintentos, prioridades y concurrencia entre procesos; si son unas pocas ejecuciones al año y un solo proceso, traerla es más pieza que problema.

Leer sin bloquear, escribir sin memoria

La construcción tiene dos mitades con reglas opuestas.

Leer quiere una foto coherente: una transacción REPEATABLE READ para que lo que se escriba a mitad no deje el paquete inconsistente. Pero una transacción abierta mientras suben gigas es una transacción que se queda abierta demasiado tiempo, así que dentro solo se leen filas y claves de almacenamiento; los ficheros se leen después, fuera.

Cuidado con el tiempo por defecto: en Prisma, una transacción interactiva corta a los 5 segundos si no le pasas timeout. Es el error que solo aparece con el primer cliente grande.

Escribir quiere no acumular: el empaquetador escribe sobre un stream que va directo al almacenamiento, que lo sube por partes. Entre los dos se cuela un Transform que calcula el SHA-256 y el tamaño al vuelo — leer el fichero otra vez para sumarlo sería doblar el trabajo.

Ahí hay una trampa fácil: si una mitad falla hay que destruir el stream para que la otra se entere, y el stream destruido necesita un manejador de error, o el proceso entero se cae. Sin eso, una subida que falla deja al empaquetador esperando a alguien que ya no existe.

La descarga, días después

Ya no es la respuesta a “generar”, sino una petición aparte, y eso cambia tres cosas:

En la petición En segundo plano
Token De un solo uso Vale varias veces, vida corta
Range No aplica Necesario
Suma No hay nada que comparar Se entrega y va como ETag

El token deja de ser de un solo uso justamente por el tamaño: una descarga de gigas se corta, y el gestor de descargas reanuda con Range sobre la misma URL. Un token que se gasta en el primer byte convierte cada corte en empezar de cero.

Caducar es parte del diseño

Un paquete con todos los datos de alguien, en reposo, es el peor objeto del sistema. Existe porque tiene que seguir disponible un tiempo, y deja de existir en cuanto ese tiempo pasa: un cron borra el fichero y marca la fila EXPIRED.

La fila se queda, sin fichero: es la constancia de que el paquete se generó y se entregó. Borrar la fila con el objeto sería borrar la prueba junto con el dato.

Qué probar