Tecnología · GUÍA PRÁCTICA
¿SpooledTemporaryFile tocó disco o se leyó vacío? Audita rollover y posición
Separa el rollover oculto por fileno del cursor en EOF antes de entregar el stream.

SpooledTemporaryFile tiene dos trampas independientes: fileno() puede llevar un payload pequeño al disco y un cursor dejado en EOF puede dar una lectura vacía al consumidor.
Usa API pública para identificar el trigger, haz seek(0), define un contrato de bytes o descriptor y prueba entrega y política de almacenamiento en el consumidor real.
1. Separa estado de almacenamiento y posición
Registra el objeto entregado, max_size, bytes escritos, tell() y llamadas a fileno(). Puede seguir en memoria y estar en EOF, o estar en disco y conservar el mismo EOF.
No uses _file ni _rolled privados como contrato; observa el directorio temporal en una prueba aislada y envuelve solo el límite que controlas.
2. Identifica el trigger de rollover
Python documenta tres triggers: superar un max_size no nulo, llamar fileno() o llamar rollover(). En CPython actual, el valor 0 desactiva el trigger por tamaño, no los otros dos.
Audita la ruta real de biblioteca, framework o subprocess. Una API de descriptor puede llamar fileno() de forma oculta y es incompatible con una política sin disco.
3. Reinicia el cursor antes de entregar
Tras escribir, llama seek(0) antes del siguiente lector. El stdin vacío del issue de CPython tenía el cursor al final; rollover no promete rebobinarlo.
Con FastAPI UploadFile usa await upload.seek(0) en async; en sync usa el método público permitido y define quién hace el close final.
4. Elige un contrato de entrega
Si acepta bytes, usa pipe, BytesIO o el resultado de read para conservar no-disk. Si exige descriptor, haz rollover explícito, confirma espacio, seek(0), entrega y cierre por el owner.
Para salida duradera copia a un destino elegido y define fsync o atomic replace; un temporary file no es una interfaz de persistencia.
5. Prueba ambos ejes en el límite real
Escribe un payload distintivo, anota tell(), rebobina, llama al consumidor real y compara el resultado. Ejecuta casos bajo umbral y con rollover forzado.
Añade un test double que registre fileno() y observa el directorio temporal aislado. Valida entrega, política de almacenamiento y limpieza por separado.
