How to deploy Kotlin services without waking up production at 3 AM
Imagine: you roll out an update to your Kotlin microservice, and suddenly — bang! — users see a 502 error, and StackTraces turn red in the logs. Sound familiar? If your team practices deployment with a 30-second service stop, then every release is a lottery. But there's good news: zero-downtime deployment of Kotlin solves this problem once and for all.
In this article, I'll show you three real strategies used in production: rolling update, blue-green deployment, and graceful shutdown. You'll get ready-made Kotlin code examples for Ktor and Spring Boot that you can implement today. Let's go.
Why zero-downtime deployment is not a luxury, but a necessity
When your service stops responding for even 10 seconds, it's not just a technical failure. It's lost customers, decreased conversion, and a blow to your reputation. Modern users don't tolerate delays. And if you work with financial transactions or streaming data — downtime can cost millions.
Zero-downtime deployment (or seamless deployment) allows you to update code without breaking connections. Users don't even notice that the service just restarted. This is especially relevant for Kotlin developers because JVM applications don't start instantly — and every second of downtime is noticeable.
Let's break down the main strategies from simple to complex.
Strategy 1: Graceful shutdown — the essential foundation
Before moving to complex orchestrations, make sure your Kotlin service can shut down gracefully. Graceful shutdown is the application's ability to finish processing current requests before shutting down. Without this, even a rolling update won't save you: you'll just kill active connections.
Implementing graceful shutdown in Ktor
Ktor supports graceful shutdown out of the box. But by default, it only waits 5 seconds. That's not enough for production. Let's configure it:
fun Application.module() { install(Shutdown) { timeout = 30.seconds // Wait up to 30 seconds onShutdown = { log.info("Shutdown hook: finishing active requests") closeResources() } }
routing { get("/") { call.respondText("Hello, Zero-Downtime!") } }}
fun closeResources() { // Close connection pool, kafka consumer, etc. println("Resources released")}The key point: timeout should be greater than the maximum processing time of a single request. If your endpoint sometimes takes 15 seconds to respond — set the timeout to 20-25 seconds.
Graceful shutdown in Spring Boot on Kotlin
In Spring Boot 2.3+, graceful shutdown is configured with a single line in application.yml:
server: shutdown: graceful
spring: lifecycle: timeout-per-shutdown-phase: 30sAnd in code, you can add a hook to release resources:
@Componentclass GracefulShutdownListener : ApplicationListener<ContextClosedEvent>() {
override fun onApplicationEvent(event: ContextClosedEvent) { println("Spring Boot: starting graceful shutdown") // Close WebSocket sessions, RabbitMQ, etc. }}Now, when receiving a SIGTERM signal (sent by Kubernetes or Docker), your service won't kill requests but will let them complete. This is the first step towards zero-downtime deployment.
Strategy 2: Rolling update — smooth updates without explosions
Rolling update is when you update pods (or containers) not all at once, but gradually. One old pod shuts down — one new pod starts. And so on, until everything is updated. This is the standard approach in Kubernetes.
But there's a nuance: if your Kot