Skip to content

Issue: uvicorn reload=True hardcoded in production - causes 100% CPU on parent process #61

@DeckerSU

Description

@DeckerSU

The parent uvicorn process (python main.py) consumes ~100% CPU in production due to reload=True being hardcoded in main.py. This activates StatReload — a polling-based file watcher that runs rglob + pathlib.resolve + os.stat on
every .py file in the working tree every ~0.5 seconds.

Root cause confirmed via py-spy

All flamegraph samples point to a single hot path:

  BaseReload.run                                                                                                                                                                                                                     
    → should_restart          (statreload.py:32)                                                                                                                                                                                     
      → iter_py_files         (statreload.py:52–53)                                                                                                                                                                                  
        → pathlib.Path.rglob                                                                                                                                                                                                         
          → pathlib.Path.resolve / _joinrealpath / _select_from / __hash__                                                                                                                                                           

watchfiles is not installed in the container, so uvicorn falls back to StatReload (CPU polling) instead of the inotify-based WatchFilesReload. The production container has 1,657 .py files across 478 directories being stat'd in
a tight loop — 17× more than the local dev tree due to site-packages being within scan scope.

Fix

api/main.py, line 212 — use the existing DEVMODE env var (already defined in const.py):

  -    uvicorn.run("main:app", host=API_HOST, port=API_PORT, reload=True)                                                                                                                                                            
  +    uvicorn.run("main:app", host=API_HOST, port=API_PORT, reload=DEVMODE)                                                                                                                                                         

DEVMODE is set to True only when DEVMODE=True is in the environment (see const.py:36), so it defaults to False in production with no .env changes needed.

run_api.sh also has --reload hardcoded — same fix:

  -poetry run uvicorn main:app --host ${API_HOST} --port ${API_PORT} --reload                                                                                                                                                        
  +poetry run uvicorn main:app --host ${API_HOST} --port ${API_PORT}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions