Skip to content

Commit 97efe13

Browse files
authored
fix: leave Granian backpressure at its default (#82)
1 parent f506303 commit 97efe13

3 files changed

Lines changed: 2 additions & 5 deletions

File tree

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Python is 3.14, dependencies managed by `uv`. The API is exposed on `:8000`.
3636

3737
`UseCases` group (request-scoped): one provider per use case in `app/use_cases/`. modern-di fills each dataclass field by its type, so a use case needs no `kwargs`.
3838

39-
**Pool and server sizing**: `DB_POOL_SIZE` (positive) and `DB_MAX_OVERFLOW` (non-negative) size the pool, and `app/__main__.py` sets Granian's `backpressure` to their sum, so each worker accepts only as many requests at once as it has connections. Requests beyond that wait in Granian's socket backlog instead of queueing on the pool. `APP_WORKERS` sets the Granian worker count, and each worker has its own pool. `DB_POOL_TIMEOUT` (default 30 s) bounds the wait for a connection, and a timeout returns 503 through `exceptions.database_unavailable_handler`. advanced-alchemy wraps the timeout in a `RepositoryError`, so the handler is also registered for `RepositoryError` and answers anything not caused by a pool timeout the way Litestar's default handler would: the debug page when `SERVICE_DEBUG` is on, a plain 500 otherwise. `DB_POOL_RECYCLE` defaults to SQLAlchemy's `-1` (never). Set it below the idle timeout of any proxy or load balancer in front of Postgres, so a connection it dropped is not handed out and retried after a 1-2 s backoff.
39+
**Pool and server sizing**: `DB_POOL_SIZE` (positive) and `DB_MAX_OVERFLOW` (non-negative) size the pool, and a request that finds it empty waits for a connection. Granian's `backpressure` is left at its default: it limits open connections per worker, idle keep-alive ones included, so setting it to the pool size makes new connections wait while the app is idle. `APP_WORKERS` sets the Granian worker count, and each worker has its own pool. `DB_POOL_TIMEOUT` (default 30 s) bounds the wait for a connection, and a timeout returns 503 through `exceptions.database_unavailable_handler`. advanced-alchemy wraps the timeout in a `RepositoryError`, so the handler is also registered for `RepositoryError` and answers anything not caused by a pool timeout the way Litestar's default handler would: the debug page when `SERVICE_DEBUG` is on, a plain 500 otherwise. `DB_POOL_RECYCLE` defaults to SQLAlchemy's `-1` (never). Set it below the idle timeout of any proxy or load balancer in front of Postgres, so a connection it dropped is not handed out and retried after a 1-2 s backoff.
4040

4141
**Use cases and lost connections**: `pool_pre_ping` is off by default (`DB_POOL_PRE_PING`). A pooled connection that died while idle is handled by `db_retry.postgres_retry` instead, which saves a round trip on every checkout. That only works if the retried function owns its whole transaction, so every use case has this shape:
4242

‎app/__main__.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
address=settings.app_host,
1212
port=settings.app_port,
1313
workers=settings.app_workers,
14-
backpressure=settings.db_pool_size + settings.db_max_overflow,
1514
interface=Interfaces.ASGI,
1615
log_level=settings.log_level,
1716
loop=Loops.uvloop,

‎tests/test_main.py‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@ def test_main(monkeypatch: pytest.MonkeyPatch) -> None:
1717
granian = mock.Mock()
1818
monkeypatch.setattr("granian.Granian", granian)
1919
monkeypatch.setattr(settings, "app_workers", 4)
20-
monkeypatch.setattr(settings, "db_pool_size", 5)
21-
monkeypatch.setattr(settings, "db_max_overflow", 2)
2220

2321
runpy.run_module("app.__main__", run_name="__main__")
2422

2523
assert granian.call_args.kwargs["workers"] == 4 # noqa: PLR2004
26-
assert granian.call_args.kwargs["backpressure"] == 7 # noqa: PLR2004
24+
assert "backpressure" not in granian.call_args.kwargs
2725

2826

2927
async def test_session() -> None:

0 commit comments

Comments
 (0)