feat: add services.pgbouncer#2885
Conversation
|
I couldn't run tests locally, so would appreciate CI (my nix.conf includes a github token) |
Logic gaps (would fail even after the above):
|
PerchunPak
left a comment
There was a problem hiding this comment.
Oh wow, I really messed this up, sorry. I fixed the tests, addressed all raised issues, and added a custom generator for key=value sections ([databases], [users] and [peers])
|
|
||
| # { foo = { bar = "baz"; } } -> foo = bar=baz | ||
| pairsToString = lib.mapAttrsToList (name: value: "${name}=${toString value}"); | ||
| genLine = pairs: lib.concatStringsSep " " (pairsToString (filterNulls pairs)); |
There was a problem hiding this comment.
Please let me know if I overengineered this
There was a problem hiding this comment.
yes, there is lib.generators.getINI, we could also adopt our files."...".ini by not creating the file by just referencing the path
There was a problem hiding this comment.
I am not sure what you are talking about. I greped nixpkgs, home-manager, and devenv, but couldn't find getINI anywhere
domenkozar
left a comment
There was a problem hiding this comment.
Thanks for this — nicely structured module that follows the existing port-allocation conventions, and the option docs are clear. A few things to address before merge:
🔴 Blocking — users option type is wrong
users = lib.mkOption {
type = types.attrsOf (types.either types.str types.int);
example = { user1 = { pool_mode = "session"; pool_size = 200; }; };The type says each user maps to a str/int, but the example and the [users] section semantics map each user to an attrset of settings. So the example itself fails type-checking, and parseKeyValueSections cfg.users calls lib.filterAttrs on a str/int and errors. It should be:
type = types.attrsOf (types.attrsOf (types.either types.str types.int));The current test only exercises databases, which is why this slipped through — could you add coverage for users and peers too?
🟠 port = 0 (Unix socket) path is unreachable
The port description says port 0 makes PgBouncer listen on a Unix socket only, but ports.main.allocate = cfg.port auto-allocates the first free port at or above the base, so listen_port always ends up non-zero. Either special-case port == 0 (skip allocation, set listen_port = 0) or drop that line from the docs.
🟠 Overlapping config paths
settings is types.anything and any attrs-valued key in it becomes its own ini section, while there are also dedicated databases/users/peers options appended as separate sections. Setting e.g. peers in both produces two [peers] sections. Worth picking one mechanism (the dedicated options) and not advertising section-attrs inside settings, or documenting precedence.
Minor
.test.shhardcodes ports 5555/6666, but those are base values — if occupied, the allocator picks different ports and the test breaks. A comment noting this would help.- Empty databases/users/peers still emit a header + blank line;
lib.optionalString (section != "")keeps the output clean. - The test uses
auth_type = "trust"— fine for CI, but maybe showscram-sha-256in the option example so users aren't nudged towardtrust.
Once the users type is fixed (plus a test for it) and the port = 0 doc/behavior is reconciled, this looks good to go. 🙏
That was intentional, because anything that is not an attrset, technically is in the global section (later it is moved to the
Added a
While I did not see any other section, I would also like to try to keep future-compatibility.
That is also my concern, devenv sometimes fails to cleanup after failed tests. But this is how every test for postgres works, and a couple of others, so I don't know what to do here. I'd prefer to stick with the existing patterns in the codebase
Fixed, thanks for catching
I couldn't make tests work with real auth (it always asks interactively for a password), so had to use |
Add a module for PgBouncer, a lightweight connection pooler for PostgreSQL.