You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:22:43