For steps that need to run before the web application starts, such as
scheduling tasks, this new `startup.py` script is introduced.
This fixes a recently introduced issue where task scheduling was not
being triggered, because of it being included in the
`if __name__ == "__main__":` block, which is not executed when
the application is run by Gunicorn in production environments.
We do not include this logic as part of FastAPI's lifespan
implementation, as running multiple workers with Gunicorn would
cause this logic to be executed multiple times.
This change replaces the `httpx` client with `aiohttp` for the
RetroAchievements API service.
The main reason for this change is that `httpx` has an unavoidable log
line with `INFO` level, which includes the request full URL, containing
the user's API key.
`httpx` has had an
[open discussion](https://github.com/encode/httpx/discussions/2765)
regarding this security issue for almost two years.
The change to `aiohttp` is painless, and would allow us to migrate more
of the codebase to it in the future, to avoid leaking sensitive
information in logs.
This change initializes the Sentry SDK, which enables error tracking
when the `SENTRY_DSN` environment variable is set.
Drop-in alternatives to Sentry are also supported, like GlitchTip.
Fix FastAPI and nginx configuration, to make the application correctly
redirect URLs. This is specially useful when URLs ended with forward
slash are redirected to their stripped version.
Included changes:
* Stop removing the `/api` prefix in nginx rewrite rules, so FastAPI
knows what's the original URL path being requested.
* Use `$http_host` in nginx, so FastAPI receives both the original host
and port, to build the redirect URL (as `$host` does not include the
port, if present).
* Make all FastAPI included routers know their prefix, to correctly
route incoming requests.
This fix was found based on a report that redirects from URLs ended with
forward slash were not working [1].
[1] https://github.com/rommapp/romm/issues/1051#issuecomment-2269049762
Pytest v8.2 introduced the `PYTEST_VERSION` environment variable [1],
that can be used to check if code is running from within a pytest run.
This way, we can avoid checking the loaded `sys` modules.
[1] https://docs.pytest.org/en/stable/changelog.html#id57
With the introduction of non-paginated responses for ROMs, JSON
responses for big collection could easily be at >1MiB.
This change adds a FastAPI-provided middleware to enable GZip
compression for responses greater than 1KiB.
This change avoids blocking requests when retrieving covers from
SteamGridDB, which is the main bottleneck as the current implementation
iterates over paginated results for multiple games.
Using an asynchronous client like `httpx` provides a good performance
improvement, and reduces the latency when calling this endpoint.
Also, the inclusion of FastAPI `lifespan` allows instantiating a single
client on startup.
When testing with "Final Fantasy V Advance", the endpoint goes from ~9s
to ~1.5s to retrieve all covers.