VeePeenini, Part 8: Moving the Server Without Losing the Game
· Vitor Pontual · 3 min read
For a few weeks the app just worked. My friends were opening packs every morning, filling their albums, arguing in the lounge, making predictions before kickoff. The build was behind me and the fun was the point. Then a logistics problem landed on top of all of it: the whole thing runs on a server in my home, and a move was coming that meant shutting that server down and bringing the app back up at a second location.
The tournament does not pause for my logistics. Points were being awarded every day, albums were filling in, trades were flying back and forth. So the task wasn’t “redeploy the app somewhere else.” It was “relocate a database that real people are actively using, mid-tournament, without losing a single thing they’ve earned.”
That last part is the whole job. In a game built for a closed group of friends, the fastest way to kill it is to lose someone’s points, or drop a sticker they traded for fairly. The scores are made up and the stakes are imaginary, and that is exactly why the trust is not optional. Lose one person’s progress once and the group stops believing the standings, and then there’s no game.
The rule that fell out of it
The first thing I made myself sit with, before any plan, was the uncomfortable shape of the problem: the two locations have completely separate databases. There is no shared disk between them and no live replication. If both boxes are ever serving at the same time, my friends’ actions land in two different databases that can never be merged back together. A trade recorded in one, a pack opened in the other, and the histories fork forever.
That is the failure mode that ends the project, and naming it early gave me the one rule everything else had to obey: exactly one live writer, ever. At every moment, one box and only one box is allowed to accept changes. The entire plan became a careful dance around keeping that true through the handoff.
The pieces in play
A couple of facts about the setup shaped everything that came after.
The app sits behind a Cloudflare Tunnel, so the public address can be pointed at one box or the other without me touching much by hand. That is the lever I’d eventually pull to switch which server the world talks to.
And the second location is a small, always-on machine I keep running elsewhere, which is a different kind of computer entirely. The home server is an ordinary x86 box; the second one is an ARM machine. That difference sounds like trivia and it is not, and it was the first thing to bite us.
I’d done plenty of ordinary deploys. I had never done a live cutover of a database that people were in the middle of using. This was going to need a real plan, and the plan went wrong in several instructive ways before it went right. That’s Part 9.