Golang Echo服务器重启后恢复下载:优雅停机与中断标记问题
解决方案:Echo服务器优雅停机与下载中断处理
一、实现优雅停机,等待活跃连接完成
Echo框架支持通过Shutdown方法实现优雅停机,结合信号监听捕获Ctrl+C(SIGINT)信号,触发停机时等待所有活跃请求处理完成。
修改后的代码:
package main import ( "context" "net/http" "os" "os/signal" "syscall" "time" "github.com/labstack/echo/v4" ) func main() { e := echo.New() e.GET("/file", func(c echo.Context) error { return c.Attachment("big_file.zip", "original file name.zip") }) // 启动服务器在goroutine中,避免阻塞主协程监听信号 go func() { if err := e.Start(":1323"); err != nil && err != http.ErrServerClosed { e.Logger.Fatal("服务器启动失败") } }() // 监听终止信号:Ctrl+C(SIGINT)、系统终止(SIGTERM) quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit // 创建带超时的上下文,设置最大等待时间防止无限期挂起 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := e.Shutdown(ctx); err != nil { e.Logger.Fatal(err) } e.Logger.Info("服务器已优雅停机") }
关键说明:
- 用goroutine启动服务器,让主协程专注监听终止信号
Shutdown方法会停止接收新请求,同时等待所有已处理中的请求完成后再关闭服务器- 超时时间可根据业务需求调整,比如大文件下载可设置更长时间
二、主动中断连接并标记下载失败(可选)
如果不需要等待连接完成,而是要让客户端立即感知下载失败,可通过中间件跟踪活跃连接,收到停机信号时主动关闭连接:
带连接跟踪的实现代码:
package main import ( "context" "net" "net/http" "os" "os/signal" "sync" "syscall" "time" "github.com/labstack/echo/v4" ) // connectionTracker 跟踪所有活跃连接 type connectionTracker struct { activeConns map[net.Conn]struct{} mu sync.Mutex } // Middleware Echo中间件,用于跟踪连接 func (ct *connectionTracker) Middleware(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { // 获取当前请求的连接 conn := c.Request().Context().Value(http.LocalAddrContextKey).(net.Conn) ct.mu.Lock() ct.activeConns[conn] = struct{}{} ct.mu.Unlock() // 监听连接关闭事件,从跟踪列表中移除 go func() { <-c.Request().Context().Done() ct.mu.Lock() delete(ct.activeConns, conn) ct.mu.Unlock() }() return next(c) } } func main() { e := echo.New() ct := &connectionTracker{activeConns: make(map[net.Conn]struct{})} // 注册连接跟踪中间件 e.Use(ct.Middleware) e.GET("/file", func(c echo.Context) error { return c.Attachment("big_file.zip", "original file name.zip") }) go func() { if err := e.Start(":1323"); err != nil && err != http.ErrServerClosed { e.Logger.Fatal("服务器启动失败") } }() quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit // 主动关闭所有活跃连接 ct.mu.Lock() for conn := range ct.activeConns { conn.Close() } ct.mu.Unlock() // 关闭服务器 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := e.Shutdown(ctx); err != nil { e.Logger.Fatal(err) } e.Logger.Info("服务器已停机") }
说明:
- 通过自定义中间件跟踪所有活跃连接,收到终止信号时主动关闭
- 客户端会收到连接中断错误,下载会被标记为失败,重启服务器后可通过Range请求头续传
总结
优先选择优雅停机方案,既能保证用户完成大文件下载,又能安全关闭服务器;若业务需要立即中断所有连接,可使用连接跟踪主动关闭的方式,让客户端感知错误以便后续续传。
内容的提问来源于stack exchange,提问作者Doubidou
相关产品推荐
相关产品推荐

