# How the Graceful Shutdown Mechanism Works in Kratos Application Lifecycle

> Understand Kratos graceful shutdown. Learn how Kratos orchestrates signal handling pre-stop hooks deregistration context cancellation post-stop hooks and server stops.

- Repository: [Kratos/kratos](https://github.com/go-kratos/kratos)
- Tags: internals
- Published: 2026-03-02

---

**Kratos orchestrates graceful shutdown through the `App` type defined in [`app.go`](https://github.com/go-kratos/kratos/blob/main/app.go), triggering an ordered sequence of pre-stop hooks, service deregistration, context cancellation, post-stop hooks, and coordinated server stops when the process receives `SIGTERM`, `SIGINT`, or `SIGQUIT` signals.**

The go-kratos/kratos microservices framework provides a sophisticated lifecycle management system that ensures applications terminate cleanly without dropping active connections or leaving orphaned service registrations. Understanding the **graceful shutdown mechanism** is essential for building production-ready Go services that handle deployment rollbacks, container orchestration signals, and maintenance windows without data loss.

## Signal Handling and Shutdown Triggers

The shutdown process begins in the `Run()` method of the `App` type, located in [[`app.go`](https://github.com/go-kratos/kratos/blob/main/app.go)](https://github.com/go-kratos/kratos/blob/main/app.go). When the application starts, it creates a signal channel and registers the OS signals specified in the `Signal` option—defaulting to `SIGTERM`, `SIGQUIT`, and `SIGINT`—via `signal.Notify`.

A goroutine spawned at lines 33‑42 waits for either context cancellation (triggered by internal errors) or an incoming signal. Upon detection, it invokes `a.Stop()`, initiating the graceful shutdown sequence. Alternatively, developers can trigger shutdown programmatically by calling `App.Stop()` directly.

## The Ordered Shutdown Sequence

Inside `Stop()`, the framework executes a precise six-step choreography to ensure resources release in the correct order:

### 1. Pre-Stop Hooks (BeforeStop)

Before any network operations cease, `Stop()` executes all functions registered with the `BeforeStop` option. Defined in [[`options.go`](https://github.com/go-kratos/kratos/blob/main/options.go)](https://github.com/go-kratos/kratos/blob/main/options.go) at lines 11‑15, these hooks run sequentially to perform early cleanup tasks such as flushing metrics, closing database connections, or stopping background workers.

### 2. Service Deregistration

If a service registrar is configured, the application deregisters itself from the service registry (lines 63‑69 in [`app.go`](https://github.com/go-kratos/kratos/blob/main/app.go)). This step prevents new traffic from routing to the terminating instance. The operation respects the `RegistrarTimeout` option, ensuring the deregistration attempt does not hang indefinitely.

### 3. Root Context Cancellation

The application cancels its root context via `a.cancel()` (line 71), propagating the cancellation signal to all downstream goroutines and components that utilize the `App` context via `NewContext`. This notifies every part of the system that shutdown is in progress, allowing in-flight requests to complete naturally.

### 4. Post-Stop Hooks (AfterStop)

After context cancellation, `Stop()` executes all `AfterStop` functions (lines 47‑50). These hooks run when the application has already stopped accepting new work but before transport servers fully terminate, making them ideal for final logging or releasing resources that depend on the context being closed.

### 5. Server Shutdown Coordination

Each transport server added via the `Server` option participates in an `errgroup`. During `Run()`, a dedicated stop routine registers for every server within the inner `eg.Go` block (lines 4‑12). When the root context cancels, these routines unblock and apply the `StopTimeout` duration (lines 6‑10) before invoking `server.Stop(stopCtx)`, giving each protocol handler (HTTP, gRPC, etc.) time to drain connections.

### 6. Error Propagation

The `errgroup` waits for all start and stop operations to complete. If any component returns an error other than `context.Canceled`, it bubbles up from `Run()` (lines 43‑45), allowing the main function to distinguish between graceful termination and actual failures.

## Configuring Shutdown Behavior

The framework exposes several functional options to tune the **graceful shutdown mechanism**:

- **Custom Signals**: Override the default signal list using `kratos.Signal(os.Interrupt, os.Kill)`.
- **Stop Timeout**: Set `kratos.StopTimeout(5 * time.Second)` to limit how long each server spends draining connections.
- **Registrar Timeout**: Configure `kratos.RegistrarTimeout(10 * time.Second)` to control service deregistration deadlines.
- **Lifecycle Hooks**: Use `kratos.BeforeStop(func(ctx context.Context) error { ... })` and `kratos.AfterStop(...)` to inject custom logic.

## Complete Implementation Example

The following example demonstrates a Kratos application configured with custom timeouts and cleanup hooks:

```go
package main

import (
	"context"
	"net/url"
	"os"
	"time"

	"github.com/go-kratos/kratos/v2"
	"github.com/go-kratos/kratos/v2/transport/http"
)

func main() {
	// Create an HTTP server
	srv := http.NewServer(
		http.Address(":8080"),
	)

	// Build the application with lifecycle hooks
	app := kratos.New(
		kratos.Name("demo.service"),
		kratos.Version("v1.0.0"),
		kratos.Server(srv),

		// Optional: custom signal list
		kratos.Signal(os.Interrupt, os.Kill),

		// Hook executed before service deregistration
		kratos.BeforeStop(func(ctx context.Context) error {
			// Flush metrics, close DB connections
			return nil
		}),

		// Hook executed after context cancellation
		kratos.AfterStop(func(ctx context.Context) error {
			// Final log message
			return nil
		}),

		// Graceful-stop timeout for each server
		kratos.StopTimeout(5 * time.Second),
	)

	// Run blocks until shutdown signal received
	if err := app.Run(); err != nil {
		// Handle non-cancellation errors
	}
}

```

In this implementation, `app.Run()` blocks indefinitely until the process receives an interrupt signal, at which point the **graceful shutdown mechanism** executes the configured hooks and timeouts in sequence.

## Summary

- The **`App`** type in [`app.go`](https://github.com/go-kratos/kratos/blob/main/app.go) orchestrates shutdown via `Run()` and `Stop()` methods.
- **Signal handling** defaults to `SIGTERM`, `SIGQUIT`, and `SIGINT`, customizable via the `Signal` option.
- **BeforeStop** hooks execute first for resource cleanup, followed by service **deregistration** from the registry.
- **Context cancellation** propagates to all components, after which **AfterStop** hooks run.
- **Transport servers** shut down concurrently with individual `StopTimeout` deadlines enforced via `errgroup`.
- Errors other than `context.Canceled` propagate upward for visibility into shutdown failures.

## Frequently Asked Questions

### What signals trigger graceful shutdown in Kratos?

By default, Kratos registers `SIGTERM`, `SIGQUIT`, and `SIGINT` via `signal.Notify` in the `Run()` method. You can customize this list by passing `kratos.Signal()` with specific `os.Signal` values when constructing the application.

### How do I add custom cleanup logic during shutdown?

Use the `BeforeStop` and `AfterStop` functional options. `BeforeStop` functions execute before service deregistration and context cancellation, making them suitable for closing database pools. `AfterStop` functions run after context cancellation, ideal for final logging or releasing context-dependent resources.

### What happens if a server exceeds the StopTimeout?

If a transport server does not stop within the duration specified by `StopTimeout`, the context passed to `server.Stop()` will expire. The specific behavior depends on the server implementation, but the `errgroup` will continue and eventually return, ensuring the process does not hang indefinitely.

### How does Kratos handle service registry deregistration failures?

The deregistration step respects the `RegistrarTimeout` option. If the registry client cannot complete deregistration within this window, the operation times out and the shutdown proceeds to context cancellation and subsequent steps, preventing a hanging registry from blocking application termination.