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

Golang Windows服务优雅停机问题求助:等待任务完成再停止

Golang Windows服务停止问题解决方案

问题1:time.sleep被中断的原因及修复

time.sleep被中断是因为http请求的上下文会在连接关闭时被取消——如果你的底层任务依赖请求上下文(比如r.Context()),当服务触发停止、http.Server开始关闭连接后,活跃请求的上下文会被取消,导致依赖该上下文的sleep或任务被中断。另外,直接用time.sleep等待任务完成本身就不可靠,应该用sync.WaitGroup跟踪所有正在执行的底层任务。

修复步骤:

  • 在服务结构体中添加sync.WaitGroup,用于统计正在运行的任务数
  • 在每个请求处理函数的开头调用wg.Add(1),任务结束时调用wg.Done()
  • 停止服务时,先调用http.Server.Shutdown()关闭监听,再调用wg.Wait()等待所有任务完成,替代time.sleep

示例代码片段:

type webService struct {
    server *http.Server
    wg     sync.WaitGroup
}

// 请求处理函数示例
func (ws *webService) handleRequest(w http.ResponseWriter, r *http.Request) {
    ws.wg.Add(1)
    defer ws.wg.Done()

    // 模拟耗时业务任务
    select {
    case <-time.After(5 * time.Second):
        fmt.Fprintf(w, "任务完成")
    case <-r.Context().Done():
        // 可选:处理上下文取消的场景
        return
    }
}

问题2:刚启动停止时Windows报错的修复

Windows服务要求收到停止命令后,必须立即反馈"正在停止"的状态,否则系统会判定服务无响应并抛出报错。需要在case svc.Stop, svc.Shutdown:分支开头添加状态报告,告知Windows服务正在处理停止请求,最后在停止完成后报告最终状态。

修复代码片段:

func (ws *webService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
    const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
    changes <- svc.Status{State: svc.StartPending}
    // 启动http服务的逻辑...
    changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}

    for {
        select {
        case c := <-r:
            switch c.Cmd {
            case svc.Stop, svc.Shutdown:
                // 1. 向Windows报告服务进入停止待处理状态
                changes <- svc.Status{State: svc.StopPending, Accepts: cmdsAccepted}

                // 2. 关闭http服务监听,不再接收新请求
                err := ws.server.Shutdown(context.Background())
                if err != nil {
                    // 处理关闭错误
                }

                // 3. 等待所有底层任务执行完毕
                ws.wg.Wait()

                // 4. 向Windows报告服务已停止
                changes <- svc.Status{State: svc.Stopped}
                return
            // 其他命令的处理逻辑...
            }
        }
    }
}

额外注意事项

  • 所有耗时任务(包括请求结束后异步启动的goroutine)都必须被WaitGroup跟踪,避免遗漏
  • http.Server.Shutdown()会自动等待活跃连接处理完成(可传入带超时的上下文控制等待时长),但异步任务必须单独用WaitGroup管理
  • 禁止用time.sleep替代WaitGroup,固定等待时间无法保证任务真的完成

内容的提问来源于stack exchange,提问作者user1956194

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 19:16:14