An election site has the most unforgiving traffic shape on the public web.
For eleven months of the year it is quiet. Then, for roughly four hours on a single evening, it takes more traffic than the rest of the year combined — from people who are refreshing, who all arrive within the same few minutes as results are posted, and who are already primed to be suspicious of anything that looks wrong.
Commerce sites get spikes too, but a retailer can announce a sale at 9am and warm everything up in advance. Nobody schedules an election night’s curiosity. And when a store is briefly slow you lose a sale, which is measurable and recoverable. When public election information is unreachable, you get a different category of problem entirely: people conclude something is being hidden.
We run public election information for the Anderson County Election Commission. Here is what that actually involves.
Cache far more aggressively than usual
The single biggest lever, and the one that gets underused because caching on a normal site is a performance nicety rather than a survival strategy.
On election night, the origin server should be serving almost nothing. Every anonymous visitor asking for the same results page should be answered from cache at the edge, not by generating that page again from the database.
Concretely:
- Full-page caching at the CDN, not just static assets. The results page is the hot path and it is identical for every visitor, which makes it perfectly cacheable.
- Short TTLs rather than no caching. People assume frequently-updating content can’t be cached. It can — you just cache it for thirty or sixty seconds instead of a day. A results page cached for one minute serves thousands of requests from a single origin hit, and nobody perceives a one-minute delay on returns that update every twenty.
- Stale-while-revalidate. When the cached copy expires, serve the slightly-old one immediately while fetching the fresh one in the background. Visitors never wait for a regeneration, and a slow origin degrades into slightly stale results rather than errors.
- Cache-key discipline. One stray query string or tracking parameter can fragment your cache into thousands of separate entries, each requiring its own origin hit. This is a common way a cache appears configured and does nothing.
- Pre-warm before the polls close. Request the pages you expect to be hot so the first real visitor isn’t the one paying for a cold cache.
If nothing else on this list gets done, aggressive caching alone handles a large share of the load.
Scale out horizontally, and do it beforehand
The other half is capacity, and the important word is horizontal.
Scaling up — a bigger server — helps until it doesn’t, and it involves downtime to change. Scaling out means several servers behind a load balancer, sharing the work. Add nodes for the night, remove them the following week.
- Add nodes ahead of time, not during. Provisioning under load is how a bad night becomes a worse one. Capacity goes in days before, tested.
- Health checks that actually check something. A node that accepts TCP connections while its database connection pool is exhausted will happily receive traffic and fail it. Check a real page, not a port.
- Don’t depend on sticky sessions. If a visitor’s experience only works when they keep hitting the same node, losing a node breaks those users. Keep session state in a shared store, or better, keep the hot pages stateless so it doesn’t matter.
- Read replicas for the database. Election-night traffic is overwhelmingly reads. Point them at replicas and leave the primary free for the writes that post results.
- Static exports where possible. The most reliable results page is a file on disk. If results can be generated as static HTML and pushed out each time they update, you have removed the application and the database from the request path entirely. Nothing scales better than a file.
The parts that aren’t infrastructure
Half of what makes election night uneventful is discipline in the days before.
Load test in advance. Not on the night. Generate realistic traffic against the real pages and find the ceiling while there is time to raise it. The failure you find in a load test is a task; the same failure at 8pm is an incident.
Freeze changes. No deployments the week of. Everything that will run that night should have been running unchanged for days. Election night is the worst possible time to discover what an unrelated plugin update did.
Have a static fallback. A plain HTML page that can be swapped in if something goes badly wrong, saying what is known and when the next update is expected. Being reachable and honest beats being unreachable.
Watch it live. Monitoring that pages somebody is the difference between a two-minute problem and a two-hour one. On these nights, someone should simply be looking.
Fix your logging first. If there’s a load balancer in front of your web servers, your access logs will show the balancer’s IP on every request rather than the visitor’s — which makes them useless precisely when you need them. That’s a configuration problem with a known fix, and it is worth sorting out well before the night. We wrote about the log format side of that years ago, with an updated note on the better modern approach.
Most of this isn’t about elections
Election night is just the clearest example, because the deadline is fixed, the traffic is guaranteed, and the consequences of being down are public.
But the same pattern applies to anything with a concentrated spike: a ticket release, a seasonal booking window, a product launch, a news mention. If your site has one night a year that matters more than the other three hundred and sixty-four, the work is the same — cache hard, scale out ahead of time, test before rather than during, and have somebody watching.
If you’re running something with a date attached to it, we’ve done this and we’d rather have the conversation months out than the week of. That’s also what server maintenance is for the rest of the year.
