Skip to content

High availability

Walis runs as a single process by default. It also runs as several processes sharing one database. Nothing about how you write jobs changes between the two.

Choosing a database

ProviderMultiple nodesNotes
SQLiteNoThe default. One file, no server to run.
PostgreSQLYes
MySQL / MariaDBYes
SQL ServerYesAzure SQL included.

SQLite is a single file. Pointing two API nodes at one SQLite file does not give you high availability, it gives you corruption — so Walis treats SQLite as inherently single-node and does not try to coordinate.

Set the provider explicitly:

ConnectionStrings__Walis=Host=db.internal;Database=walis;Username=walis;Password=…
Database__Provider=postgresql

Leaving Database__Provider unset makes Walis guess from the connection string. A wrong guess fails at startup rather than halfway through a build, which is the cheaper of the two failures.

What changes when clustered

/health tells you which mode you are in:

json
{ "status": "ok", "database": "PostgreSQL", "node": "walis-a", "clustered": true }

With clustered: true:

  • Builds are claimed atomically. Two nodes can try to take the same queued build; exactly one wins the transition from Queued to Running. The loser moves on.
  • Nodes poll for work. A build queued by node A does not appear in node B's in-memory queue, so each node also polls the database. On SQLite this path is skipped entirely.
  • Once-only work is leased. Cron evaluation, offline-runner detection, retention cleanup and scheduled backups run on whichever node currently holds the lease. Leases expire, so if the holder dies another node picks the work up on its next pass — there is no separate coordination service to run or to lose.
  • Interrupted-build recovery is scoped to the node. A node restarting only recovers the builds it was running, not another node's.

What does not change: job definitions, actions, plugins, runners, notifications and the API. A remote runner does not know or care how many API nodes exist.

Moving from SQLite to a server database

The backup archive is engine-agnostic, so the migration is a backup and a restore:

  1. Take a backup on the SQLite deployment (Settings → Backup).
  2. Point a node at the new database.
  3. Restore the archive.
  4. Start the remaining nodes against the same connection string.

Restore clears the target first, so restore into the new database before you put traffic on it. See Backup and restore.

What HA does and does not buy you

It removes the API server as a single point of failure and lets you take a node down for upgrades without a maintenance window.

It does not make your builds redundant. A build is running on one node or one runner; if that machine dies mid-build, the build fails and has to be re-run. And your database becomes the thing that must stay up — Walis has no opinion on how you make PostgreSQL highly available.

Released under the MIT License.