Merge pull request 'Forge database pool caps are config values, and a changed value recreates the forge (issue 1966, recovery)' (#633) from fix/1966-gitea-pool-config into main

This commit was merged in pull request #633.
This commit is contained in:
2026-11-08 03:41:23 +00:00
3 changed files with 42 additions and 6 deletions
+3 -3
View File
@@ -7,6 +7,6 @@ GITEA__database__PASSWD=${secret:postgres-database}
GITEA__webhook__ALLOWED_HOST_LIST=172.17.0.1
# Issue 1966: cap the forge's own pool; the store's 100 connections are shared by every module on this machine.
# SSH git operations go through the forge's private API, so this pool carries them.
GITEA__database__MAX_OPEN_CONNS=40
GITEA__database__MAX_IDLE_CONNS=10
GITEA__database__CONN_MAX_LIFETIME=5m
GITEA__database__MAX_OPEN_CONNS=${config:database-max-open-connections}
GITEA__database__MAX_IDLE_CONNS=${config:database-max-idle-connections}
GITEA__database__CONN_MAX_LIFETIME=${config:database-connection-lifetime}
+23
View File
@@ -187,6 +187,26 @@
]
},
"config": {
"database-max-open-connections": {
"type": "number",
"description": "The most connections the forge's own database pool holds open to the store. The store's 100 connections are shared by every module on its machine, and the forge's git operations over ssh go through the forge's private API, which this pool carries: 40 leaves room for the others.",
"trusted": false,
"minimum": 1,
"default": 40
},
"database-max-idle-connections": {
"type": "number",
"description": "The connections the forge's database pool keeps idle, ready for the next request. They count against the store's 100 connections, shared on its machine, so keep this well under the open-connection cap.",
"trusted": false,
"minimum": 0,
"default": 10
},
"database-connection-lifetime": {
"type": "string",
"description": "How long the forge's database pool keeps one connection before it closes and reopens it, as a duration such as 5m. A shorter lifetime gives back connections of the store's 100 connections, shared on its machine, sooner.",
"trusted": false,
"default": "5m"
},
"url": {
"type": "string",
"description": "The address the module's tools reach the forge at, as a URL; unset, the code falls back to its environment, else this machine's gitea on its port.",
@@ -286,6 +306,9 @@
{
"id": "server",
"type": "container",
"restart-on": [
"server-env"
],
"health": {
"kind": "http",
"endpoint": "web",
+16 -3
View File
@@ -3,11 +3,24 @@ import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
// The forge's own database pool is capped (issue 1966): the store's connections are shared by every module on the machine.
// The caps are config values placed into the env-file, and a changed env-file recreates the container.
const env = readFileSync(new URL("../files/server.env", import.meta.url), "utf8");
const manifest = JSON.parse(readFileSync(new URL("../module.json", import.meta.url), "utf8"));
test("the forge caps its database pool", () => {
test("the forge's pool caps are config values, placed in server.env, and a change recreates the container", () => {
const lines = env.split("\n");
for (const line of ["GITEA__database__MAX_OPEN_CONNS=40", "GITEA__database__MAX_IDLE_CONNS=10", "GITEA__database__CONN_MAX_LIFETIME=5m"]) {
assert.ok(lines.includes(line), `server.env lacks ${line}`);
const placed: Record<string, [string, unknown]> = {
GITEA__database__MAX_OPEN_CONNS: ["database-max-open-connections", 40],
GITEA__database__MAX_IDLE_CONNS: ["database-max-idle-connections", 10],
GITEA__database__CONN_MAX_LIFETIME: ["database-connection-lifetime", "5m"],
};
for (const [name, [key, def]] of Object.entries(placed)) {
assert.ok(lines.includes(`${name}=\${config:${key}}`), `server.env does not place ${key} at ${name}`);
assert.equal(manifest.config[key].default, def);
assert.equal(manifest.config[key].trusted, false);
assert.ok(manifest.config[key].description.includes("100 connections"));
}
assert.equal(manifest.config["database-max-open-connections"].minimum, 1);
const server = manifest.resources.find((r: { id: string }) => r.id === "server");
assert.deepEqual(server["restart-on"], ["server-env"]);
});