Zero-downtime deployment of Swift services: how to update without downtime

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why zero-downtime deployment is not a luxury but a necessity for a Swift developer

\n

Imagine: your Swift service on Vapor processes thousands of requests per second. You release a new feature — and users get 502 Bad Gateway, while logs show SIGTERM and broken connections. Sound familiar? If you write in Swift for the backend, sooner or later you'll face the problem: how to update the service without losing a single request.

\n

Zero-downtime deployment is not magic, but a set of proven techniques that allow you to replace a running Swift binary with a new one without breaking active connections. In this article, I'll show you how to configure graceful shutdown, organize hot process replacement, and make a Swift service work with Nginx. All with real Swift code and no fluff.

\n\n

What is zero-downtime and why it matters for Swift projects

\n

Zero-downtime deployment is when you update an application and users don't notice a single millisecond of downtime. This is especially important for Swift services because:

\n
    \n
  • Clients don't tolerate errors — a broken request means lost data or money.
  • \n
  • Swift servers often work under high load (fintech, chats, real-time API).
  • \n
  • Restarting a binary can take seconds — which is an eternity for an active connection.
  • \n
\n

The classic approach — killing the old process and starting a new one — doesn't work. A Swift application on Vapor or Hummingbird must gracefully complete processing current requests, then give way to a new instance. That's exactly what all the following code is about.

\n\n

Step 1. Graceful shutdown in Swift: writing correct termination

\n

The first building block of zero-downtime is graceful shutdown. Your Swift service must be able to catch the SIGTERM signal and not break connections mid-stream. Vapor 4+ already does this out of the box, but let's check and, if needed, add custom logic.

\n\n

Basic Vapor configuration for graceful shutdown

\n
import Vapor\n\nlet app = Application()\n\n// Register the signal handler\napp.lifecycle.use(ShutdownSignalHandler())\n\n// Standard Vapor code\napp.get("health") { req in\n    return "OK"\n}\n\ntry app.run()\n
\n

But what if you need to wait for long-running tasks to complete? For example, file processing or sending emails. Let's add a custom ShutdownSignalHandler:

\n\n
import Vapor\nimport NIOCore\n\nfinal class ShutdownSignalHandler: LifecycleHandler {\n    private var runningTasks: [EventLoopFuture<Void>] = []\n    \n    func willBoot(_ app: Application) throws {\n        // Subscribe to SIGTERM\n        app.running?.onStop = {\n            print("⏳ Stop signal received. Completing active tasks...")\n            return self.runningTasks.flatten(on: app.eventLoopGroup.next())\n        }\n    }\n    \n    func registerTask(_ task: EventLoopFuture<Void>) {\n        runningTasks.append(task)\n    }\n}\n
\n

Now, when SIGTERM arrives, the server will wait for all registered tasks to complete. This is critical for zero-downtime deployment of Swift services: the old process won't kill requests it has already started processing.

\n\n

Checking in the console

\n

Start the server and send it a signal:

\n
kill -SIGTERM <PID>\n
\n

In the logs, you'll see a message about graceful termination. If everything works — move on to the next step.

\n\n

Step 2. Blue-green deployment on Swift: two binaries — zero downtime

\n

Graceful shutdown solves the problem of broken connections, but it doesn't solve the problem of update time. While the old process is shutting down, the new one must already be accepting requests. The ideal scheme is blue-green deployment.

\n

The essence is simple: you have two instances of the Swift service (blue and green). One is active, the other is on standby. When you update the code, you:

\n
    \n

Blogs

Book Recommendations