优雅关闭 #
一、优雅关闭概述 #
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