实际示例
Web 服务器的优雅关闭
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
server := &http.Server{Addr: ":8080"}
// 启动 HTTP 服务器
go func() {
if err := server.ListenAndServe(); err!= http.ErrServerClosed {
log.Fatalf("HTTP 服务器错误: %v", err)
}
}()
// 信号处理
stopChan := make(chan os.Signal, 1)
signal.Notify(stopChan, syscall.SIGINT, syscall.SIGTERM)
<-stopChan
log.Println("正在关闭服务器...")
// 带超时的优雅关闭
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err!= nil {
log.Fatalf("服务器关闭错误: %v", err)
}
log.Println("服务器已停止")
}
信号处理工作流程
graph TD
A[服务器运行] --> B[接收到信号]
B --> C[停止接受新连接]
C --> D[完成现有请求]
D --> E[优雅关闭]
E --> F[服务器停止]
后台任务管理
package main
import (
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time"
)
func backgroundTask(id int, stopChan <-chan struct{}, wg *sync.WaitGroup) {
defer wg.Done()
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
fmt.Printf("任务 %d 正在运行...\n", id)
case <-stopChan:
fmt.Printf("任务 %d 正在停止...\n", id)
return
}
}
}
func main() {
// 取消机制
stopChan := make(chan struct{})
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
// 用于任务同步的 WaitGroup
var wg sync.WaitGroup
// 启动多个后台任务
for i := 0; i < 3; i++ {
wg.Add(1)
go backgroundTask(i, stopChan, &wg)
}
// 等待终止信号
<-signalChan
close(stopChan)
// 等待所有任务完成
wg.Wait()
fmt.Println("所有任务已停止")
}
信号处理场景
场景 |
信号 |
操作 |
Web 服务器关闭 |
SIGTERM |
停止接受新连接 |
长时间运行的进程 |
SIGINT |
保存状态并退出 |
资源清理 |
SIGKILL |
立即终止 |
关键要点
- 使用 context 进行超时管理
- 实现干净的关闭机制
- 处理多个并发任务
- 提供优雅降级
在LabEx,我们建议进行全面的信号处理,以构建能够优雅响应系统中断的健壮Go应用程序。