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.Volumeis 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
FUSElayer, whose per-request random reads are slow enough to stall video playback, whileModal'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/apibase) and serving the built frontend as a single-page app for everything else -
Wraps the server's
lifespaninmodal_host_lifespan, which adds the local-disk + volume-sync persistence without changing the core lifespan
Access Gate
-
When
MIRUMOJI_WEB_PASSWORDis set, the whole app is wrapped in HTTP Basic Auth (seeBasicAuthMiddleware) -
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
( |
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
FUSEwrite can never keep the container alive pastModal'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 |