What goes into a launch?

image

Our first launch

We recently did a soft launch of the new season system along with our first batch of seasonal content, the Hanseatic League. A soft launch means we opened the doors quietly with a working season running live so we could watch real players move through it before we made any more noise.

I wanted to take some time to go into the details of what actually goes into a launch, and especially into a new season, because most of the work is invisible. When it goes well, players just see new content appear. What follows is everything underneath that.

The season system

A season is not a mode you flip on inside the existing game. When a season is active, the game runs as two parallel worlds at the same time.

There is the standard realm, our permanent world that never resets, and the season realm, a fresh world with its own database where the actual seasonal play happens. Each world has its own background worker, the process that ticks resource production, resolves combat, completes buildings, and so on. So during a season we are really running two full copies of the game economy side by side, each unaware of the other.

This split exists so that players can get a competitive start with new content and a clear finish line, but without losing the estate they've spent months building. The season is where new mechanics, balance changes, and limited-time content land first while the permanent world keeps ticking along untouched.

At the end of a season, a merge script is the only path that moves seasonal content into the permanent world. Nothing gets added to standard by hand ahead of time. This prevents a whole category of bugs where content exists in one world but not the other.

A nice property of the design is that a lot of the season bookkeeping is lazy. Instead of running a big migration to reset everyone's seasonal stats when a season starts, each player's record carries a small stamp saying which season it belongs to. The first time the game touches a stale record, it resets that piece on the spot. No downtime, no migration window, no worker job that has to sweep every player. The reset just happens quietly as people play.

Making content

A launch is basically running down a checklist, and the checklist matters more than any single clever step.

Build the content in the season world, not the permanent one. Every new building, balance number, and reward goes into the season realm first. This is the default.

Make every migration and one-off script realm-aware. A script that only touches the permanent database silently skips the world players are actually on. So anything that touches data has to loop over every database that exists, standard and season. Every now and then a script only touches standard, when it should have targeted the seasonal realm, it works perfectly in testing and on a local machine, then does nothing on the live season, because the change never reached the right world.

Deploy

A push to the server triggers a hook that runs the deploy script, pulls the new code, and restarts the processes. Before all that the system runs a comprehensive automatic test suite (full suite is > 2000 tests at this point).

The API server and workers reloads on its own. We then publish patch notes to both worlds. Patch notes are stored per database, so a note written only to the permanent world is invisible to the people playing the season. They have to go into both if applicable.

We then smoke test the live world. Walk the core loop as a real player on the season realm: build something, send a caravan, run a fight, claim a reward.

When things go wrong

A lot of what can go wrong on launch traces back to the two-world split, or to the gap between the API and the workers.

The single most common type of bug is "it works in tests but not on prod." Nine times out of ten that means a change or a migration only ever reached the permanent world and never touched the season database where players actually are. Tests pass because tests spin up a clean database every run. The live season is the one place that doesn't get a fresh start.

There is also a hardware reality that shapes how we work. Our server is relatively small, and we learned the hard way that running the full test suite on it during deploy could spike memory hard enough to send the whole machine into a death spiral of disk thrashing. So tests run locally as the source of truth, and the deploy itself skips them. That's a deliberate trade we made to keep the box healthy, and it means discipline before pushing matters more.

When something does break live, the priority order is: stop it from corrupting data, restore the core loop, then chase the cosmetic stuff. A frozen estate that can't save is an emergency. A misaligned sprite can wait.

The unknown, unknown

No amount of pre-launch testing finds the bugs that only exist when real people are playing. This is the part of a launch that you cannot checklist your way through, because by definition you don't yet know what you're looking for.

Tests run against a clean, empty world. The live season is messy, it has players with odd estate layouts, half-finished queues, edge-case combinations of gear and units nobody thought to try, and the sheer volume of a real economy ticking over. The "interesting" bugs hide in that mess and they tend to surface only once dozens of estates are all being processed at once, or once a player does something in an order you never tested, or once a record has been written and rewritten enough times to drift into a state your tests never produced.

So the real work of the unknown unknowns is live triage. You sit with the running game, you watch the logs and the players, and you fix small things in flight while the world keeps turning. Every fix is a change to a world that has real players in it right now, so you can't take it down, can't reset it, and can't undo a bad write. A migration to repair one player's broken record has to be careful not to touch the records that are fine. A worker restart to ship a fix is a few seconds where ticks pause for everyone.

It's a different kind of engineering from building the feature. Building is unhurried and reversible. Live fixing is surgical: small, reversible-where-possible changes, verified against the actual running world, with one eye always on "what else does this touch." The bugs are usually tiny, but the cost of fixing them carelessly is not.

The takeaway from our first seasonal launch is that this phase never fully ends.

If you want to try out our game and the new season, you can do so for free at:

Imperia Borealis

← Back to all posts