Skip to content

App

app

Defines the FastAPI application that the mirumoji-host Modal app runs

Builds a FastAPI application that serves the built React frontend and mounts the server's routers under /api, so a single Modal ASGI app answers both the SPA and the API on one origin

Local-Disk Data With Background Volume Sync
  • The persistent modal.Volume is not mounted on the path where the server reads and writes user data. Instead the server operates on the container's local disk (CONTAINER_CACHE) and a background task mirrors every change to the volume mount (DATA_MOUNT)

  • This keeps media serving and database access off the volume's FUSE layer, whose per-request random reads are slow enough to stall video playback, while Modal's background and shutdown volume commits still persist the data durably

The server's own create_app factory is left untouched. This wraps its lifespan (never modifying it) and reuses its exception handlers and routers by import

create_host_app(frontend_dir)

Builds the FastAPI application server by the mirumoji-host Modal app

Additive
  • Does not modify or call server.app.create_app

  • Reuses the server's exception handlers and routers by import, mounting the routers under /api (matching the frontend's relative /api base) and serving the built frontend as a single-page app for everything else

  • Wraps the server's lifespan in modal_host_lifespan, which adds the local-disk + volume-sync persistence without changing the core lifespan

Access Gate
  • When MIRUMOJI_WEB_PASSWORD is set, the whole app is wrapped in HTTP Basic Auth (see BasicAuthMiddleware)

  • When it is unset, the app is served open and a warning is logged, which is only expected in local development

Non-Local Import

The core mirumoji package deps don't cover FastAPI or the server extra deps which importing from server pull, however this function is only ever executed inside a Modal container that is running mirumoji's CPU-Backend docker image, which has mirumoji installed with the server extra, which is why it exists here in the launcher sub-package

Parameters:

Name Type Description Default
frontend_dir Path

The directory holding the built frontend (index.html plus hashed assets)

required

Returns:

Type Description
FastAPI

The configured host application

modal_host_lifespan(host_app) async

Wraps the server's core lifespan with the host's local-disk + volume-sync persistence, without modifying the core lifespan

Startup Steps
  • Ensures the local cache exists

  • Warms it from the volume (restoring the user's data on a redeploy or restart)

  • Starts the background volume syncer BEFORE the core lifespan, so every file the core startup writes (the database, the media tree) is mirrored to the volume

  • Runs the core lifespan

Shutdown

After the core lifespan's teardown (so the database is already closed)

  • A watchdog is armed at shutdown onset so a stranded FUSE write can never keep the container alive past Modal's grace

  • Cancels the syncer

  • Modal's background and final volume commits persist everything the syncer copied, so no explicit reconciliation or commit is needed

Core Untouched

The server's lifespan runs verbatim through async with, so the Docker deployment that shares it is unaffected

Parameters:

Name Type Description Default
host_app FastAPI

The host application whose lifecycle is managed

required

Yields:

Type Description
AsyncIterator[None]

Control to the running application, matching the core lifespan's yield