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

如何在Golang包中启动不阻塞主程序的Web服务器

问题解决:Go包启动Web服务器同时主程序正常完成并保持服务器运行

问题根源分析

  1. 直接调用RunServer阻塞主程序:原代码中log.Fatal(http.ListenAndServe(...))会先阻塞在ListenAndServe(该方法会一直运行直到服务器停止),一旦出现错误还会直接调用os.Exit终止程序,导致主程序无法执行完自身逻辑。
  2. goroutine中启动服务器无法访问:主程序执行完自身逻辑后会直接退出,Go运行时会终止所有未完成的goroutine,服务器进程还未稳定启动就被杀死,因此浏览器无法连接。

解决方案

步骤1:修改包内代码,移除log.Fatal并支持优雅关闭

调整包的RunServer函数,返回服务器实例和错误,同时保存http.Server对象用于后续优雅关闭:

package mypackage

import (
    "context"
    "log"
    "net/http"
)

type HandleServer struct {
    mux    *http.ServeMux
    server *http.Server
}

func NewMux() *HandleServer {
    return &HandleServer{
        mux: http.NewServeMux(),
    }
}

// RunServer 启动Web服务器,返回服务器实例和启动错误
func RunServer() (*HandleServer, error) {
    h := NewMux()
    h.registerHandlers()
    h.server = &http.Server{
        Addr:    ":8001",
        Handler: h.mux,
    }

    // 启动服务器在goroutine中,避免阻塞调用方
    go func() {
        if err := h.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Printf("服务器运行异常: %v", err)
        }
    }()

    return h, nil
}

func (h *HandleServer) registerHandlers() {
    h.mux.HandleFunc("/", h.rootHandler)
}

func (h *HandleServer) rootHandler(w http.ResponseWriter, r *http.Request) {
    _, _ = w.Write([]byte("root handler"))
}

// Shutdown 优雅关闭服务器
func (h *HandleServer) Shutdown(ctx context.Context) error {
    return h.server.Shutdown(ctx)
}

步骤2:主程序调用逻辑调整

主程序在完成自身业务逻辑后,需要等待信号来保持程序运行,确保服务器goroutine持续存活,同时支持优雅关闭:

package main

import (
    "context"
    "log"
    "mypackage"
    "os"
    "os/signal"
    "syscall"
    "time"
)

func main() {
    // 执行主程序自身业务逻辑
    log.Println("主程序业务逻辑执行完成")

    // 启动Web服务器
    server, err := mypackage.RunServer()
    if err != nil {
        log.Fatalf("服务器启动失败: %v", err)
    }

    // 监听中断信号(Ctrl+C 或者系统终止信号)
    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
    <-sigChan

    // 优雅关闭服务器,等待5秒处理剩余请求
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    if err := server.Shutdown(ctx); err != nil {
        log.Fatalf("服务器关闭失败: %v", err)
    }

    log.Println("服务器已优雅关闭")
}

关键说明

  • 包内不再使用log.Fatal,而是将错误返回给主程序处理,避免直接终止整个进程。
  • 主程序通过监听系统信号保持运行状态,确保服务器goroutine可以持续处理请求。
  • 新增的Shutdown方法支持优雅关闭服务器,允许处理完当前正在进行的请求后再停止。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 03:42:15