优雅关闭 #

一、优雅关闭概述 #

1.1 什么是优雅关闭 #

优雅关闭是指在停止服务时,先完成正在处理的请求,再关闭服务。

1.2 为什么需要优雅关闭 #

  • 避免请求中断
  • 防止数据丢失
  • 释放资源
  • 完成清理工作

二、基本实现 #

2.1 监听信号 #

go
package main

import (
    "context"
    "log"
    "os"
    "os/signal"
    "syscall"
    "time"
    
    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()
    
    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Hello, World!")
    })
    
    // 启动服务(非阻塞)
    go func() {
        if err := app.Listen(":3000"); err != nil {
            log.Fatal(err)
        }
    }()
    
    // 监听中断信号
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
    <-quit
    
    log.Println("Shutting down server...")
    
    // 优雅关闭
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    
    if err := app.ShutdownWithContext(ctx); err != nil {
        log.Fatal("Server forced to shutdown:", err)
    }
    
    log.Println("Server stopped")
}

2.2 使用Shutdown #

go
go func() {
    if err := app.Listen(":3000"); err != nil {
        log.Println("Server stopped:", err)
    }
}()

quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
<-quit

if err := app.Shutdown(); err != nil {
    log.Fatal("Shutdown error:", err)
}

三、完整示例 #

3.1 带清理的优雅关闭 #

go
package main

import (
    "context"
    "log"
    "os"
    "os/signal"
    "syscall"
    "time"
    
    "github.com/gofiber/fiber/v2"
)

type App struct {
    fiber *fiber.App
    db    *Database
    cache *Cache
}

func NewApp() *App {
    return &App{
        fiber: fiber.New(),
        db:    NewDatabase(),
        cache: NewCache(),
    }
}

func (a *App) Setup() {
    a.fiber.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Hello")
    })
}

func (a *App) Run() error {
    go func() {
        if err := a.fiber.Listen(":3000"); err != nil {
            log.Println("Server stopped:", err)
        }
    }()
    
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
    <-quit
    
    return a.Shutdown()
}

func (a *App) Shutdown() error {
    log.Println("Shutting down...")
    
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    
    // 关闭HTTP服务
    if err := a.fiber.ShutdownWithContext(ctx); err != nil {
        log.Println("HTTP shutdown error:", err)
    }
    
    // 关闭数据库
    if err := a.db.Close(); err != nil {
        log.Println("Database close error:", err)
    }
    
    // 关闭缓存
    if err := a.cache.Close(); err != nil {
        log.Println("Cache close error:", err)
    }
    
    log.Println("Shutdown complete")
    return nil
}

func main() {
    app := NewApp()
    app.Setup()
    
    if err := app.Run(); err != nil {
        log.Fatal(err)
    }
}

四、超时处理 #

4.1 设置超时 #

go
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

if err := app.ShutdownWithContext(ctx); err != nil {
    log.Println("Shutdown timeout:", err)
}

4.2 分阶段关闭 #

go
func (a *App) Shutdown() error {
    // 1. 停止接受新请求
    log.Println("Stopping new requests...")
    
    // 2. 等待现有请求完成
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    
    if err := a.fiber.ShutdownWithContext(ctx); err != nil {
        log.Println("HTTP shutdown error:", err)
    }
    
    // 3. 关闭数据库连接
    log.Println("Closing database...")
    a.db.Close()
    
    // 4. 关闭缓存
    log.Println("Closing cache...")
    a.cache.Close()
    
    // 5. 关闭其他资源
    log.Println("Closing other resources...")
    
    return nil
}

五、健康检查 #

5.1 关闭状态检查 #

go
var isShuttingDown bool

app.Get("/health", func(c *fiber.Ctx) error {
    if isShuttingDown {
        return c.Status(503).JSON(fiber.Map{
            "status": "shutting down",
        })
    }
    return c.JSON(fiber.Map{
        "status": "healthy",
    })
})

// 关闭时设置标志
func (a *App) Shutdown() error {
    isShuttingDown = true
    // ...
}

六、总结 #

6.1 优雅关闭步骤 #

text
1. 监听中断信号
2. 停止接受新请求
3. 等待现有请求完成
4. 关闭数据库连接
5. 关闭其他资源
6. 退出程序

6.2 下一步 #

现在你已经掌握了优雅关闭,接下来让我们学习 数据库概述,了解Fiber如何与数据库集成!

最后更新:2026-03-28