Skip to content

Temp file cleanup#80

Open
emmanuelmingo wants to merge 2 commits intoindictechcom:masterfrom
emmanuelmingo:Temp-File-CLeanup
Open

Temp file cleanup#80
emmanuelmingo wants to merge 2 commits intoindictechcom:masterfrom
emmanuelmingo:Temp-File-CLeanup

Conversation

@emmanuelmingo
Copy link
Copy Markdown

Improve temporary file handling and prevent resource leaks

This PR fixes file handle leaks and ensures temporary files created during uploads are always cleaned up, regardless of whether the upload succeeds or fails.

Problem

Temporary files downloaded to temp_images/ were never deleted after an upload completed. Over time this would cause disk usage to grow unboundedly. Additionally, the async Celery task opened file handles without guaranteeing cleanup on failure.

Changes

utils.py — Added cleanup_temp_file() helper that safely removes a temp file and logs a warning on failure without raising, so cleanup errors never interrupt the response.
app.py — Wrapped the synchronous process_upload() call in a try/finally block so the temp file is deleted on both success and UploadError.
tasks.py — Wrapped the entire async task body in a try/finally block so the temp file is deleted after the Celery task finishes, whether it succeeded or failed.
Outcome

No orphaned files left in temp_images/ after any upload path (sync or async)
No leaked file handles
Cleanup failures are logged as warnings and never surface to the client

emmanuelmingo and others added 2 commits March 24, 2026 21:36
Introduces a custom exception hierarchy, structured rotating file-based
logging, standardised API error responses, and proper error tracking for
asynchronous Celery tasks.

Changes
-------
exceptions.py (new)
  - WikifileTransferError as root base for all application exceptions
  - APIError(HTTPException) as base for HTTP-facing errors; subclasses:
    ValidationError (422), NotFoundError (404), AuthenticationError (401),
    UploadError (502), ExternalAPIError (502)
  - Internal exceptions: DownloadError, DatabaseError, TaskError

logging_config.py (new)
  - configure_logging() sets up a RotatingFileHandler (5 MB / 3 backups)
    writing to logs/app.log plus a console handler
  - Extracted from app.py so logging config lives in its own module

error_handlers.py (updated)
  - register_error_handlers() now logs HTTP errors at WARNING and
    unexpected exceptions at ERROR with full traceback
  - All responses follow a consistent envelope:
    {"success": bool, "data": {}, "errors": [...]}

app.py (updated)
  - Import and call configure_logging() from logging_config
  - Raise ValidationError / AuthenticationError / ExternalAPIError /
    DownloadError / DatabaseError at every failure point instead of
    returning manual JSON error responses
  - /api/task_status: fix PROGRESS state data (use task.info) and
    SUCCESS state data (use task.result); remove non-serialisable result
  - Replace bare except: clauses with specific exception types
  - Standardise response envelope to use "errors" list throughout

utils.py (updated)
  - download_image: raise DownloadError instead of returning None;
    specific messages for network errors, missing imageinfo, disk failures
  - process_upload: raise UploadError instead of returning None;
    specific messages for CSRF, network, file-read, and wiki-rejection
  - get_localized_wikitext: replace bare except with RequestException
    and (KeyError, IndexError) handlers; log at appropriate levels
  - All file handles opened with context managers (with open(...))

tasks.py (updated)
  - Add structured logging with task_id on every log line
  - Wrap each stage (CSRF fetch, file upload, response parse) in
    try/except raising TaskError so Celery marks the task FAILURE
  - File opened with context manager to prevent handle leaks
  - Remove unused import os

tests/ (new)
  - tests/conftest.py: session-scoped Flask test client with MWOAuth
    and Celery mocked out; auth_client fixture for authenticated routes
  - tests/test_exceptions.py: 33 tests covering inheritance chain,
    HTTP status codes, werkzeug compatibility, and message handling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add cleanup_temp_file() helper to utils.py that safely removes a temp
  file and logs a warning on failure without raising
- Wrap synchronous process_upload() call in app.py with try/finally so
  the temp file is deleted on both success and UploadError
- Wrap the entire async upload_image_task body in tasks.py with
  try/finally so the temp file is deleted regardless of outcome
- Remove unused UploadError import from app.py
@emmanuelmingo emmanuelmingo changed the title Temp file c leanup Temp file cleanup Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant