Skip to content

fix(backend): replace hardcoded /tmp paths with Python tempfile module#775

Open
m4cd4r4 wants to merge 6 commits intohotosm:devfrom
m4cd4r4:fix/tempfile-replace-tmp
Open

fix(backend): replace hardcoded /tmp paths with Python tempfile module#775
m4cd4r4 wants to merge 6 commits intohotosm:devfrom
m4cd4r4:fix/tempfile-replace-tmp

Conversation

@m4cd4r4
Copy link
Copy Markdown
Contributor

@m4cd4r4 m4cd4r4 commented Apr 8, 2026

Fixes #597 (backend portion).

Summary

Every backend write to a hardcoded /tmp/... path is replaced with temporary files and directories managed by the tempfile module. This stops the server's disk from filling up over time because temporary files are now cleaned up automatically (either via context managers, finally blocks, or Starlette BackgroundTasks).

Changes

app/gcp/gcp_routes.py - save_gcp_file now writes the upload via tempfile.NamedTemporaryFile(delete=False) and unlinks the file in a finally block once the S3 put returns.

app/waypoints/waypoint_routes.py - both generate_waypoint and generate_wmpl_kmz route flightplan generation through one tempfile.mkdtemp directory per request. For the download path the temp dir's lifetime is handed to FileResponse as a BackgroundTask (shutil.rmtree) so the file can still stream before being removed. For the non-download path the temp dir is removed synchronously. Errors during generation wipe the temp dir immediately. The generate_kmz_with_placemarks endpoint follows the same mkdtemp + BackgroundTask pattern.

app/waypoints/flightplan_output.py - build_flightplan_download_response gets an optional cleanup: BackgroundTask parameter that it passes through to FileResponse(background=...). This keeps the download endpoints from having to choose between "leak the file" and "delete it before FileResponse can read it".

app/projects/project_logic.py - the terrain-follow DEM path inside update_projects_flight_metrics and the process_waypoints_and_waylines helper both use tempfile.TemporaryDirectory context managers. Cleanup now happens automatically, including on exceptions, replacing the hand-rolled os.makedirs + try/finally shutil.rmtree.

app/jaxa/upload_dem.py - the DEM download worker replaces Path(f"/tmp/tif_processing/{project_id}") with tempfile.mkdtemp(prefix=f"dtm-dem-{project_id}-") and a simple finally: shutil.rmtree(...). The previous hand-rolled glob-and-unlink cleanup is gone.

app/images/image_processing.py - ODM asset download now uses tempfile.mkdtemp(prefix=\"dtm-odm-\"). The existing finally block already removed the directory, so behaviour is preserved.

app/projects/classification_routes.py - the reflight download endpoint now writes the KMZ inside a tempfile.mkdtemp directory and schedules shutil.rmtree as a BackgroundTask instead of os.remove on the single file.

Not in this PR

The vendored drone-flightplan package under src/backend/packages/drone-flightplan/ still has /tmp defaults in its output writers (mavlink.py, litchi.py, dji.py, qgroundcontrol.py, create_flightplan.py). Those belong upstream at hotosm/drone-flightplan and will be addressed in a follow-up PR there so this one stays reviewable.

Verification

  • python -m py_compile passes on all seven touched files
  • ruff check passes with no findings on all seven touched files
  • grep -rn "/tmp/" src/backend/app/ returns no matches other than a comment line referencing the system temp root

Test plan

  • Unit/integration suite green in CI
  • Manual: download a flightplan via POST /waypoint/task/{task_id}/ with download=true - file should be served and the temp dir should be gone from the server after the stream
  • Manual: download a reflight KMZ via the classification reflight endpoint - same expectation
  • Manual: run the JAXA DEM ARQ job against a test project - temp dir should be gone whether the job succeeds or fails

spwoodcock and others added 6 commits April 7, 2026 21:39
Refs hotosm#597.

Every backend write to a hardcoded /tmp/... path is replaced with
tempfile-managed temporary files and directories:

- GCP upload: NamedTemporaryFile + finally-unlink around the S3 put
- Waypoint flightplan generation (terrain-follow + plain): one
  tempfile.mkdtemp per request, cleaned up synchronously on the
  non-download path, or via a FileResponse BackgroundTask after the
  stream completes on the download path
- generate-kmz endpoint: same mkdtemp + BackgroundTask pattern
- project_logic.process_waypoints_and_waylines + terrain-follow DEM
  path: TemporaryDirectory context managers (cleanup on exceptions)
- jaxa/upload_dem worker: tempfile.mkdtemp + finally shutil.rmtree,
  replacing the hand-rolled per-project cleanup
- image_processing ODM download: tempfile.mkdtemp (existing rmtree
  cleanup in finally was already correct)
- reflight download endpoint: tempfile.mkdtemp + BackgroundTask

flightplan_output.build_flightplan_download_response gains an optional
cleanup BackgroundTask parameter so routes that write into a temp dir
can hand the directory's lifetime over to Starlette. This keeps the
download endpoints from having to choose between "leak the file" and
"delete it before FileResponse can read it".

The vendored drone-flightplan package still has /tmp defaults in its
output writers - that will be addressed in a follow-up PR against
hotosm/drone-flightplan directly to keep this PR reviewable.
@github-actions github-actions Bot added bug Something isn't working backend Related to backend code labels Apr 8, 2026
Copy link
Copy Markdown
Member

@spwoodcock spwoodcock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool! I've wanted to see this for ages - thank you 😁

Only comment so far, without a good review, is that the drone-flightplan package is actually in this repo too, under src/backend/packages/drone-flightplan, so could be updated too =)

@spwoodcock spwoodcock changed the base branch from main to dev April 20, 2026 22:21
@spwoodcock
Copy link
Copy Markdown
Member

This is really useful & appreciated, but I just realised it was made against main, instead of against the default dev branch 😅

It's significantly out of sync now - sorry!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Related to backend code bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace usage of /tmp directory with Python tempfile module

2 participants