Skip to content
Arbinel

Database

Arbinel uses Forgejo’s [database] settings. The Forgejo configuration cheat sheet describes them, and the Forgejo database preparation guide covers setting up PostgreSQL or MySQL. Arbinel adds a connection timeout, failover between several hosts, consistent reads with replicas, and a few performance changes.

[database]
CONNECT_TIMEOUT = 10s
Key Default Meaning
CONNECT_TIMEOUT 10s How long a new PostgreSQL connection may take before Arbinel gives up on that host. 0 turns it off.

Without it, a connection to a host that does not answer waits for the operating system’s TCP timeout, often about two minutes. Arbinel adds the value to the PostgreSQL connection string as connect_timeout, in whole seconds. If NAME already contains a connect_timeout parameter, for example NAME = arbinel?connect_timeout=5, Arbinel uses that value instead. MySQL and SQLite ignore the setting.

HOST_PRIMARY and HOST_REPLICA are Forgejo settings for a primary with read replicas. Both accept a comma-separated list of PostgreSQL hosts:

[database]
DB_TYPE = postgres
HOST_PRIMARY = pg-rw-1.internal:5432,pg-rw-2.internal:5432
HOST_REPLICA = pg-ro-1.internal:5432,pg-ro-2.internal:5432

Each list becomes one PostgreSQL connection string with several hosts. The driver tries the hosts in order and uses the first one that answers within CONNECT_TIMEOUT. An unreachable host delays the connection by at most that time and never blocks queries.

Forgejo instead opens a separate connection pool for each replica host. If one of those hosts is down, Forgejo can keep sending reads to it and hang.

A multi-host connection has these limits:

  • The driver does not spread load across the hosts in a list. It uses the first reachable one. To spread reads across replicas, put a load balancer such as HAProxy or PgBouncer in front of them.
  • With a single replica connection string, LOAD_BALANCE_POLICY and LOAD_BALANCE_WEIGHTS have no effect.
  • Every host in HOST_PRIMARY must accept writes when it answers. List endpoints that always lead to the current primary, for example the read-write endpoint of your PostgreSQL cluster manager.
  • With MySQL, list only one replica host. A comma-separated list does not work there.

Replicas lag behind the primary. In Forgejo, a request that writes a row and then reads it back can get the read from a replica that does not have the row yet.

Arbinel pins each HTTP request to the primary as soon as the request writes. After the request’s first write, or once it starts a transaction, all its later reads go to the primary. Requests that only read keep using the replicas.

This applies only when HOST_REPLICA is set.

Background work from queues and cron tasks is not pinned and reads from the replicas, as in Forgejo.

These need no configuration.

  • Two extra indexes on the issue table speed up issue and pull request lists. They cover (repo_id, is_closed, created_unix) and (repo_id, is_closed, is_pull) and are named repo_closed_created and repo_closed_pull. Arbinel creates them during its schema sync at startup, so the first start on a large database takes longer while Arbinel builds them.
  • The in-memory commit cache that Git tree listings use to find the last commit of each file is capped at 5,000 commits per open repository. Forgejo’s cache had no limit and could grow with every commit it resolved. The [cache.last_commit] settings still control the shared last-commit cache as in Forgejo.

If you switch back to Forgejo, its schema sync removes the two indexes again. This causes no harm.