Golang中如何创建Windows服务
Golang中如何创建Windows服务 如何为Gin REST应用创建Windows服务
2 回复
在Golang中为Gin REST应用创建Windows服务,推荐使用golang.org/x/sys/windows/svc标准库配合golang.org/x/sys/windows/svc/mgr。以下是完整实现示例:
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/gin-gonic/gin"
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/debug"
"golang.org/x/sys/windows/svc/eventlog"
"golang.org/x/sys/windows/svc/mgr"
)
// 服务结构体
type ginService struct {
server *http.Server
elog debug.Log
}
// 实现windows/svc.Handler接口
func (s *ginService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) {
changes <- svc.Status{State: svc.StartPending}
// 启动Gin服务器
go func() {
gin.SetMode(gin.ReleaseMode)
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Windows Service with Gin"})
})
s.server = &http.Server{
Addr: ":8080",
Handler: router,
}
s.elog.Info(1, "Starting Gin server on :8080")
if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
s.elog.Error(1, fmt.Sprintf("Server failed: %v", err))
}
}()
changes <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}
// 处理服务控制请求
for {
select {
case c := <-r:
switch c.Cmd {
case svc.Interrogate:
changes <- c.CurrentStatus
case svc.Stop, svc.Shutdown:
changes <- svc.Status{State: svc.StopPending}
s.elog.Info(1, "Shutting down server")
// 优雅关闭Gin服务器
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := s.server.Shutdown(ctx); err != nil {
s.elog.Error(1, fmt.Sprintf("Server shutdown failed: %v", err))
}
s.elog.Info(1, "Service stopped")
return false, 0
default:
s.elog.Error(1, fmt.Sprintf("Unexpected control request: %d", c))
}
}
}
}
// 安装服务
func installService(name, desc string) error {
exepath, err := os.Executable()
if err != nil {
return err
}
m, err := mgr.Connect()
if err != nil {
return err
}
defer m.Disconnect()
s, err := m.OpenService(name)
if err == nil {
s.Close()
return fmt.Errorf("service %s already exists", name)
}
s, err = m.CreateService(name, exepath, mgr.Config{
DisplayName: name,
Description: desc,
StartType: mgr.StartAutomatic,
})
if err != nil {
return err
}
defer s.Close()
// 配置恢复选项
err = s.SetRecoveryActions([]mgr.RecoveryAction{
{Type: mgr.ServiceRestart, Delay: 60 * time.Second},
{Type: mgr.ServiceRestart, Delay: 60 * time.Second},
{Type: mgr.NoAction, Delay: 0},
}, 0)
if err != nil {
return err
}
return eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info)
}
// 卸载服务
func removeService(name string) error {
m, err := mgr.Connect()
if err != nil {
return err
}
defer m.Disconnect()
s, err := m.OpenService(name)
if err != nil {
return fmt.Errorf("service %s is not installed", name)
}
defer s.Close()
err = s.Delete()
if err != nil {
return err
}
return eventlog.Remove(name)
}
func main() {
const svcName = "GinRESTService"
isIntSess, err := svc.IsAnInteractiveSession()
if err != nil {
log.Fatalf("Failed to determine session: %v", err)
}
if !isIntSess {
// 作为服务运行
elog, err := eventlog.Open(svcName)
if err != nil {
log.Fatal(err)
}
defer elog.Close()
service := &ginService{elog: elog}
elog.Info(1, fmt.Sprintf("Starting %s service", svcName))
err = svc.Run(svcName, service)
if err != nil {
elog.Error(1, fmt.Sprintf("%s service failed: %v", svcName, err))
return
}
elog.Info(1, fmt.Sprintf("%s service stopped", svcName))
return
}
// 命令行模式
if len(os.Args) > 1 {
cmd := os.Args[1]
switch cmd {
case "install":
err := installService(svcName, "Gin REST API Service")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Service %s installed successfully\n", svcName)
case "remove":
err := removeService(svcName)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Service %s removed successfully\n", svcName)
case "debug":
// 调试模式运行
elog := debug.New(svcName)
service := &ginService{elog: elog}
elog.Info(1, fmt.Sprintf("Starting %s in debug mode", svcName))
err = svc.Run(svcName, service)
if err != nil {
elog.Error(1, fmt.Sprintf("%s service failed: %v", svcName, err))
}
default:
fmt.Printf("Unknown command: %s\n", cmd)
fmt.Println("Usage:")
fmt.Println(" install - install service")
fmt.Println(" remove - remove service")
fmt.Println(" debug - run in debug mode")
}
return
}
// 直接运行(非服务模式)
fmt.Println("Running Gin server directly on :8080")
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Running in console mode"})
})
router.Run(":8080")
}
编译和部署步骤:
- 编译为Windows可执行文件:
GOOS=windows GOARCH=amd64 go build -o gin-service.exe
- 安装服务:
gin-service.exe install
- 启动服务:
sc start GinRESTService
- 查看服务状态:
sc query GinRESTService
- 调试运行:
gin-service.exe debug
- 卸载服务:
gin-service.exe remove
关键特性说明:
- 使用
svc.IsAnInteractiveSession()检测运行环境 - 实现
svc.Handler接口处理服务生命周期 - 支持优雅关闭HTTP服务器
- 集成Windows事件日志系统
- 支持自动重启的恢复策略
- 提供安装、卸载、调试等命令行操作
服务安装后可在Windows服务管理器中看到"GinRESTService",支持自动启动和故障恢复。


