<aside>
💡 tempfile.SpooledTemporaryFile
을 래핑한 Starlette
객체로, 클라이언트 요청에 담긴 파일을 전달 받을 수 있다.
</aside>
Temporary file wrapper, specialized to switch from BytesIO or StringIO to a real file when it exceeds a certain size or when a fileno is needed.
APIRouter
에서 이미 메모리에서 디스크로 rollover
처리 된다SpooledTemporaryFile.close()
→ 내부 TemporaryFile.close()
호출
메모리에 있는 경우 메모리 해제
디스크에 있는 파일은 OS가 삭제
OS | 삭제 방식 | 코드 구현 |
---|---|---|
POSIX | unlink() 후 파일 디스크립터 닫을 때 공간 회수 | os.unlink(name) 즉시 호출 |
Windows | O_TEMPORARY 플래그로 핸들 닫힘 시 삭제 | `flags |
사용 예시
from fastapi import UploadFile
# 단일 파일
@app.post("/uploadfile/")
async def upload_single_file(file: UploadFile): <---------------------
return {"filename": file.filename}
# 다중 파일
@app.post("/uploadfile/")
async def upload_multiple_file(file_list: list[UploadFile]): <---------------------
return ...
<aside> 💡 파일의 총 크기가 커질 수록 foreground에서 S3 저장까지 수행하게 되면 소요시간이 너무 길어 백그라운드에서 진행
</aside>
close()
처리가 되어 삭제된 이후였기 때문이다
Request
인스턴스가 요청 생애주기가 종료되어 GC에 의해 제거되는데, 이때 내부적으로 관리하는 UploadFile
도 닫히며 삭제된다delete=False
인자를 사용한 NamedTemporaryFile
를 통해 직접 임시파일들을 생성하고, 그 경로들을 background에 넘겨서 S3 업로드 및 임시파일 삭제
TemporaryFile
은 파일을 닫으면 자동 삭제되며(커스텀 불가), 백그라운드에서 해당 파일을 특정할 수 없어 NamedTemporaryFile
사용delete
(혹은 delete_on_close
) 파라미터를 false
로 설정해야 한다참고: ECS Fargate의 디스크 용량(=임시 스토리지)은 태스크 당 디폴트 20GiB
BackgroundTasks
사용 시 db 쓰기 작업 미작동ThreadPoolExecutor
스레드 수를 조절하여 재사용 [vs asyncio
의 loop.run_in_executor()
](https://fortune-lark-b0d.notion.site/vs-asyncio-loop-run_in_executor-11b1bf6ebbe581dfb343e7ff9c77439a)