Nobody has started this yet — be first.
Business impact
Thumbnail generation can fail for reasons that have nothing to do with the image itself -- a transient disk-full condition, a momentary crash in the worker, a corrupt-but-recoverable-on-retry decode. Today, once an image lands in status=failed, it is stuck there forever: there is no way, short of re-uploading the same file under a brand new id, to ask the service to try again. For a user who successfully uploaded a large, legitimate file that failed processing for a reason unrelated to the file itself, re-uploading means paying the full upload cost again for something the server already has safely on disk. Support has no self-service option to offer these users other than "please upload it again."
Problem
POST /images/{id}/retry exists as a stub only. It correctly 404s for an unknown id, but for any image it does find -- regardless of that image's actual status -- it unconditionally returns 501 NOT_IMPLEMENTED and never touches the record or schedules any work.
Current behavior
POST /images/{id}/retry always returns 501 NOT_IMPLEMENTED for any image it can find, whether that image is failed, processing, or already ready, and never reschedules the thumbnail pipeline.
Expected behavior
On a status=failed image, POST /images/{id}/retry should reset it to status=processing (clearing error_reason), schedule run_thumbnail_pipeline again as a background task -- the same function upload_image already schedules for a new upload -- and return success (200 or 202). On an image that is not failed (processing or ready), it should return 409 Conflict -- retrying only makes sense for a terminal failure; an in-flight or already-successful image must not be silently re-queued. On an unknown id it should return 404 IMAGE_NOT_FOUND (already correct in the stub).
Steps to reproduce
uvicorn app.main:app --reload
curl -s -X POST http://localhost:8000/images/<id>/retry
Why this matters
The original file is still sitting untouched in storage under record.original_key the whole time -- nothing about a failed thumbnail pass invalidates it. Retrying is therefore just "run the exact same pipeline that a normal upload runs, against the file that's already there" -- run_thumbnail_pipeline(image_id, storage, session_factory) in app/main.py is already exactly that function, already used by upload_image via background_tasks.add_task(...).
Suggested approach
Look at retry_image in app/main.py (currently a short stub right above delete_image), and compare it against how upload_image schedules run_thumbnail_pipeline after committing its own state change. You'll need the same background_tasks: BackgroundTasks dependency upload_image takes. Think about what state a status=failed record needs reset to before you reschedule the pipeline -- the pipeline itself doesn't clear error_reason on the way in, only on the way to READY.
Acceptance criteria
Verification
pytest practicetickets/test_ticket05_retry_failed_image.py -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
$git checkout -b feat/retry-failed-imageFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/retry-failed-imageSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign indocker-compose.yml./app./testsuvicorn --reload/app/dataDockerfile.proddocker compose -f docker-compose.prod.yml up --build -dWithout Docker:
cd fastapi/image_service
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
cp .env.example .env # optional, defaults work out of the box
uvicorn app.main:app --reload # -> http://127.0.0.1:8000/docs
Work the tickets in practicetickets/ (TICKET_01 through TICKET_07); each names one dedicated pytest file:
pytest practicetickets/test_ticket01_upload_size_boundary.py -v # a single ticket
./practicetickets/run_tickets.sh # all 7, clean pass/fail summary
Run run_tickets.sh from anywhere -- it cds to the project root itself before running, since app/main.py resolves its SQLite file and upload directory relative to the working directory at import time. pytest -q tests/ (the project's own pre-existing suite, separate from practicetickets/) is also worth running before and after each fix -- three of the four bugs (tickets 02, 04, 06) also break specific pre-existing tests there, and fixing the ticket correctly should make those green again too, with zero changes needed inside tests/ itself.
Level 2
Implement a feature
Extend the system within its own patterns.