Architecture
Funkwhale is made of several components, each of them fulfilling a specific mission:
![digraph {
node [shape=record];
rankdir=TB
concentrate=true
user [group="frontend" label="User" fontsize="9"]
webui [group="frontend" label="Web interface (VueJS SPA)" fontsize="9"]
subapps [group="frontend" label="Subsonic-compatible apps (DSub, Clementine)" fontsize="9"]
proxy [label="Reverse proxy (Nginx/Apache)" fontsize="9"]
api [label="API Server (Django)" fontsize="9"]
db [label="Database (PostgreSQL)" fontsize="9"]
cache [label="Cache and message queue (Redis)" fontsize="9"]
worker [label="Worker (Celery)" fontsize="9"]
scheduler [label="Task scheduler (Celery Beat)" fontsize="9"]
user -> subapps -> proxy
user -> webui -> proxy
cache -> worker
proxy -> api
api -> cache
api -> db
scheduler -> cache
worker -> cache
worker -> db
}](../_images/graphviz-19aa66ae8c48df45b05fc326006668c78d587014.png)
This graph may looks a bit scary, so we’ll detail the role of each component below.
The user
Funkwhale users can interact with your instance using:
The official web interface
Third-party apps
The web interface
This refers to Funkwhale’s built-in web interface, which is a Single Page application written in Vue JS. This application will interact with Funkwhale’s API to retrieve or persist data.
Third-party apps
Since Funkwhale implements a subset of the Subsonic API, it’s compatible with existing apps such as DSub, Ultrasonic or Clementine that support this API. Those apps can be used as a replacement or in conjunction of the web interface, but the underlying data is the same.
The reverse proxy
Funkwhale’s API server should never be exposed directly to the internet, as we require a reverse proxy (Apache or Nginx) for performance and security reasons. The reverse proxy will receive client HTTP or HTTPS requests, and:
Proxy them to the API server
Serve requested static files (audio files, stylesheets, javascript, fonts…)
The API server
Funkwhale’s API server is the central piece of the project. This component is responsible for answering and processing user requests, manipulate data from the database, send long-running tasks to workers, etc.
It’s a Python/Django application.
The database
Most of the data such as user accounts, favorites, music metadata or playlist is stored in a PostgreSQL database.
The cache/message queue
Fetching data from the database is sometimes slow or resource hungry. To reduce the load, Redis act as a cache for data that is considerably faster than a database.
It is also a message queue that will deliver tasks to the worker.
The worker
Some operations are too long to live in the HTTP request/response cycle. Typically, importing a bunch of uploaded tracks could take a minute or two.
To keep the API response time as fast as possible, we offload long-running tasks to a background process, also known as the Celery worker.
Typical tasks include:
Handling music imports
Handling federation/ActivityPub messages
Scanning other instances libraries
This worker is also able to retry failed tasks, or spawn automatically more process when the number of received tasks increase.
The scheduler
Some long-running tasks are not triggered by user or external input, but on a recurring basis instead. The scheduler is responsible for triggering those tasks and put the corresponding messages in the message queue so the worker can process them.
Recurring tasks include:
Cache cleaning
Music metadata refreshing