Hacker News new | ask | show | jobs
by capableweb 1459 days ago
Instead of talking about specific technologies/software/services, I'll give a quick rundown how you can achieve this in theory, and hopefully it can apply to whatever you're currently using.

The requirements:

- Your application should be able to run on arbitrary ports, preferably controlled with env vars or similar

- You need to have something in front of your application, like nginx or apache

- Whatever webserver you have should be able to "hang"/pause/suspend requests while you switch application version

- Each version you create needs to be concerned about what the previous version did. Breaking changes needs to happen across multiple versions, where you can soft-deprecate something, and a release after that, actually "break" it

- You need to have some sort of "healthchecking" that can tell you if the new version is OK or not

The implementation:

- You have Version 1 running of your backend on port X

- You want to deploy the new version, so you deploy it to your server but the web server in front still serves requests from Version 1

- Run healthchecks against Version 2

- Once they pass, tell web server to "pause" in-flight requests

- Switch web server configuration to use Version 2 application instead (this can be combined with the previous step, `nginx reload` would combine these for example)

- Stop Version 1 from running

- Repeat for each new version

And now you've achieved deploying a new version of your application without any failing requests.

(Sidenote: You can replace hanging/pausing requests with graceful shutdown of your webserver (meaning it waits for no pending requests) if you have a low amount of traffic)

2 comments

While this is right, I'm not sure why you mentioned pausing requests. If you can run v1 and v2 at the same time, you could switch where the new requests are going without affecting the old ones. There's many ways to do that, but what I do is point nginx upstream at a path which is a symlink to a Unix socket of a specific version. So it's more like: start the new version, check, update symlink, wait until old connections drop, kill old version.
Yeah, nginx and apache have ways of reloading the configuration without dropping requests (by waiting for existing ones to finish with old workers, and spinning up new workers with the new config in the case of nginx) but doesn't apply in every situation (like when you're not using nginx) so figure I'd write about the general principle instead of specifically for nginx.
You can do this with (or without) any proxy too. Iptables (due to conntrack) can make decisions about the first packet in a connection, then save the result. That means you can match incoming traffic on --state NEW and route to a specific local port. Changing one iptables entry is atomic, so you can swap the version seamlessly this way.

I think the idea is worth mentioning because people often think it's hard to achieve / something special. But there's a hundred ways to do seamless version swap on a host.

Wow, that's a good point. Obvious in hindsight, but personally I never considered iptables for that job. Thanks for sharing this!
> Instead of talking about specific technologies/software/services, I'll give a quick rundown how you can achieve this in theory, and hopefully it can apply to whatever you're currently using.

I wish more people approached their software engineering teaching in this way.

Thank you for the great comment.

> I wish more people approached their software engineering teaching in this way.

Me too, so why not do it myself? :) Thanks for the feedback