Skip to content

Several instances

One instance is the default, and stays as simple as it is: AMS_MODE=single — SQLite or PostgreSQL, the media on disk or in a bucket, every job scheduled by the process itself. AMS_MODE=multi runs several instances as one, behind whatever balances the interface’s port between them:

  • PostgreSQL is required (AMS_DATABASE_URL=postgres://…): several processes cannot share an SQLite file.
  • The media in a bucket (AMS_MEDIA_STORAGE=s3), or kept nowhere (off): a directory is one instance’s own.
  • A cache server is required (AMS_REDIS_URL): it is the bus the instances coordinate on, besides being the second tier.

The server refuses to start in multi mode without the three, and says which is missing. With them, the instances agree on a leader through a lease on the cache server — renewed every five seconds, lost within fifteen when the leader goes, taken by another within five more — and the leader alone runs the schedules: the refresh sweep, the dataset imports, the listing, the media sweep, the certificate’s renewal. Every instance answers requests, fetches the media in line (each medium claimed by one worker), and can run a task by hand: a task is held on the cache server while it runs, so two instances never run the same. What one instance changes, the others are told through the channel: a setting, a network rule, a session revoked, a medium kept or forgotten, a run to stop, a certificate issued. The counters on Opening & APIs add up what every instance answered, and the rate limits — requests per minute, sign-ups per hour — are one quota across them all, counted on the cache server.

Two things move into the database in multi mode, so an instance started afresh serves what the others do: the key the identity provider’s cookies are sealed with, and — for the clients’ door — the authority the clients trust and the certificate it issued. An authority already kept in AMS_TLS_DIR is taken into the database the first time, so the clients need not trust a new one; back the database up accordingly, since it holds the authority’s key from then on. Each instance’s clients’ door serves that one certificate, so a client may reach any of them; the operator’s own certificate (AMS_CLIENTS_TLS_CERT / _KEY) works as before, from files every instance has.

AMS_INSTANCE_NAME names an instance among the others — set it: the hostname is the fallback, and a container’s hostname is its id unless hostname: says otherwise, so two instances or two lives of one would not be told apart. The administration’s Cache page lists them with who leads, and the dashboard says how many there are. The metrics carry ams_leader and ams_instances. The lease, the holds and the windows live on the cache server beside the cache: with allkeys-lru they are what is touched most and evicted last, but a server that runs out of memory is a server that may forget who leads — size it so that it never does, or give the instances a server of their own for coordination. compose.multi.yaml is a complete stack — PostgreSQL, Valkey, a Garage bucket, two instances, Caddy in front — and scripts/e2e-multi.sh starts two instances against a PostgreSQL of its own and checks that they agree, pass on what changes, count together and hand the lead over.

What it does not do: a multi deployment scales the requests, not the database or the bucket, which become the ceiling; with the cache server away, the caches keep to memory as before, but no instance leads and nothing scheduled runs until it answers — a request is never held up by it. A task is held on the cache server for a minute at a time, renewed while it runs: a cache server restarted or evicting keys can lose the hold, and another instance asked to start the same task in that minute would run it a second time — wasteful, never wrong.

The interface’s port of every instance is published by whatever balances them — Caddy, in compose.multi.yaml. What that proxy has to send, and what the instances need to know of it, is in Behind a reverse proxy.