在 Go 語言中,信號處理是通過 os/signal 包來實現的。信號是操作系統向進程發送的異步通知,常用於進程間通信和系統管理。最常見的信號包括 SIGINT(Ctrl+C)和 SIGTERM(優雅終止信號)。
信號處理最佳實踐
常用信號類型 :
// 常見信號定義
const (
SIGINT = syscall.SIGINT // 中斷信號 (Ctrl+C)
SIGTERM = syscall.SIGTERM // 終止信號
SIGHUP = syscall.SIGHUP // 掛起信號 (重新加載配置)
SIGUSR1 = syscall.SIGUSR1 // 用户自定義信號1
SIGUSR2 = syscall.SIGUSR2 // 用户自定義信號2
SIGQUIT = syscall.SIGQUIT // 退出信號 (Ctrl+\)
)
優雅關閉模式 :
- 立即關閉 (SIGINT): 快速停止,較短超時時間
- 優雅關閉 (SIGTERM): 完成當前請求後停止,較長超時時間
- 強制關閉 (SIGKILL): 無法捕獲,立即終止進程
實踐建議 :
- 始終處理 SIGTERM 信號以支持優雅關閉
- 為關閉操作設置合理的超時時間
- 使用 Context 來協調多個 goroutine 的關閉
- 記錄信號處理過程以便調試
- 在生產環境中測試信號處理邏輯
常見問題與易錯點
問題1:未捕獲關鍵信號
如果程序未能捕獲到關鍵的終止信號(如SIGINT、SIGTERM),可能導致進程無法正常結束,需要用户強制 kill。
// 錯誤:未註冊任何信號處理器
解決辦法:使用signal.Notify註冊至少包括SIGINT和SIGTERM在內的關鍵信號處理器。
問題2:信號處理不當導致程序崩潰
在信號處理器中執行復雜的操作或阻塞操作可能導致程序崩潰或響應延遲。
// 錯誤:在信號處理器中執行耗時操作
func signalHandler(sigCh <-chan os.Signal) {
for range sigCh {
timeConsumingOperation()
}
}
解決辦法:信號處理器應儘可能簡潔,僅負責通知主程序執行清理邏輯。複雜的操作應在主程序中異步處理。
問題3:忽略信號處理後的清理邏輯
未執行必要的清理邏輯(如關閉文件、釋放資源、保存狀態等)可能導致資源泄漏、數據丟失等問題。
// 錯誤:收到信號後直接退出,未執行清理邏輯
func signalHandler(sigCh <-chan os.Signal) {
for range sigCh {
os.Exit(0)
}
}
解決辦法:在信號處理器中觸發清理流程,確保程序優雅退出。清理完成後,使用return語句退出主程序。
後面很多代碼是AI寫的,我也只是學習看懂而已。
002.go
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
fmt.Println("=== 基礎信號處理演示 ===")
// 創建一個接收信號的通道
sigChan := make(chan os.Signal, 1)
// 註冊要監聽的信號
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
fmt.Println("程序運行中... 按 Ctrl+C 發送 SIGINT 信號")
fmt.Println("或使用 'kill -TERM <pid>' 發送 SIGTERM 信號")
// 啓動一個 goroutine 模擬工作
go func() {
for i := 1; ; i++ {
fmt.Printf("工作中... 計數: %d\n", i)
time.Sleep(2 * time.Second)
}
}()
// 等待信號
receivedSignal := <-sigChan
fmt.Printf("\n收到信號: %v\n", receivedSignal)
// 執行清理工作
fmt.Println("執行清理工作...")
time.Sleep(1 * time.Second)
fmt.Println("程序優雅退出")
}
Go 應用程序可以通過處理終止信號(SIGTERM、SIGINT)來實現優雅關閉,這是生產環境中的重要實踐 。
優雅關閉 HTTP 服務器的例子
003.go
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
fmt.Println("=== HTTP 服務器優雅關閉演示 ===")
// 創建 HTTP 服務器
server := &http.Server{
Addr: ":8080",
Handler: createHandler(),
}
// 在 goroutine 中啓動服務器
go func() {
fmt.Println("HTTP 服務器啓動在 :8080")
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("服務器啓動失敗: %v", err)
}
}()
// 創建信號通道
quit := make(chan os.Signal, 1)
// 註冊信號處理
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
// 等待信號
sig := <-quit
fmt.Printf("\n收到信號: %v,開始優雅關閉...\n", sig)
// 創建帶超時的上下文
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// 優雅關閉服務器
if err := server.Shutdown(ctx); err != nil {
log.Printf("服務器強制關閉: %v", err)
} else {
fmt.Println("服務器優雅關閉完成")
}
}
func createHandler() http.Handler {
mux := http.NewServeMux()
// 普通處理器
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello! 當前時間: %s\n", time.Now().Format("2006-01-02 15:04:05"))
})
// 模擬長時間處理的端點
mux.HandleFunc("/slow", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("開始處理慢請求...")
time.Sleep(10 * time.Second) // 模擬長時間處理
fmt.Fprintf(w, "慢請求處理完成: %s\n", time.Now().Format("2006-01-02 15:04:05"))
fmt.Println("慢請求處理完成")
})
// 健康檢查端點
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "OK")
})
return mux
}
多信號處理和自定義處理邏輯
004.go
package main
import (
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time"
)
type Application struct {
workers []Worker
shutdown chan struct{}
wg sync.WaitGroup
isShutdown bool
mu sync.RWMutex
}
type Worker struct {
id int
name string
quit chan struct{}
}
func NewApplication() *Application {
return &Application{
workers: make([]Worker, 0),
shutdown: make(chan struct{}),
}
}
func (app *Application) AddWorker(id int, name string) {
worker := Worker{
id: id,
name: name,
quit: make(chan struct{}),
}
app.workers = append(app.workers, worker)
}
func (app *Application) Start() {
fmt.Println("=== 多信號處理演示 ===")
// 啓動所有工作器
for i := range app.workers {
app.wg.Add(1)
go app.runWorker(&app.workers[i])
}
// 設置信號處理
app.setupSignalHandling()
fmt.Println("應用程序啓動完成,等待信號...")
// 等待關閉信號
<-app.shutdown
fmt.Println("等待所有工作器完成...")
app.wg.Wait()
fmt.Println("應用程序完全關閉")
}
func (app *Application) runWorker(worker *Worker) {
defer app.wg.Done()
fmt.Printf("工作器 %s (ID: %d) 啓動\n", worker.name, worker.id)
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
app.mu.RLock()
if app.isShutdown {
app.mu.RUnlock()
fmt.Printf("工作器 %s (ID: %d) 檢測到關閉信號,停止工作\n", worker.name, worker.id)
return
}
app.mu.RUnlock()
fmt.Printf("工作器 %s (ID: %d) 正在工作... %s\n",
worker.name, worker.id, time.Now().Format("15:04:05"))
case <-worker.quit:
fmt.Printf("工作器 %s (ID: %d) 收到退出信號\n", worker.name, worker.id)
// 模擬清理工作
fmt.Printf("工作器 %s (ID: %d) 執行清理工作...\n", worker.name, worker.id)
time.Sleep(1 * time.Second)
fmt.Printf("工作器 %s (ID: %d) 清理完成\n", worker.name, worker.id)
return
}
}
}
func (app *Application) setupSignalHandling() {
sigChan := make(chan os.Signal, 1)
// 註冊多個信號
signal.Notify(sigChan,
syscall.SIGINT, // Ctrl+C
syscall.SIGTERM, // 終止信號
syscall.SIGHUP, // 掛起信號(通常用於重新加載配置)
syscall.SIGUSR1, // 用户自定義信號1
syscall.SIGUSR2, // 用户自定義信號2
)
go func() {
for {
sig := <-sigChan
fmt.Printf("\n收到信號: %v\n", sig)
switch sig {
case syscall.SIGINT:
fmt.Println("處理 SIGINT (Ctrl+C) - 立即關閉")
app.handleShutdown(false)
return
case syscall.SIGTERM:
fmt.Println("處理 SIGTERM - 優雅關閉")
app.handleShutdown(true)
return
case syscall.SIGHUP:
fmt.Println("處理 SIGHUP - 重新加載配置")
app.handleReload()
case syscall.SIGUSR1:
fmt.Println("處理 SIGUSR1 - 打印狀態信息")
app.printStatus()
case syscall.SIGUSR2:
fmt.Println("處理 SIGUSR2 - 切換調試模式")
app.toggleDebugMode()
}
}
}()
}
func (app *Application) handleShutdown(graceful bool) {
app.mu.Lock()
if app.isShutdown {
app.mu.Unlock()
fmt.Println("已經在關閉過程中...")
return
}
app.isShutdown = true
app.mu.Unlock()
if graceful {
fmt.Println("開始優雅關閉...")
// 通知所有工作器停止
for i := range app.workers {
close(app.workers[i].quit)
}
// 設置超時
go func() {
time.Sleep(10 * time.Second)
fmt.Println("優雅關閉超時,強制退出")
close(app.shutdown)
}()
} else {
fmt.Println("立即關閉...")
close(app.shutdown)
}
// 等待一段時間後發送關閉信號
go func() {
time.Sleep(2 * time.Second)
close(app.shutdown)
}()
}
func (app *Application) handleReload() {
fmt.Println("重新加載配置...")
// 這裏可以實現配置重新加載邏輯
fmt.Println("配置重新加載完成")
}
func (app *Application) printStatus() {
app.mu.RLock()
defer app.mu.RUnlock()
fmt.Println("=== 應用程序狀態 ===")
fmt.Printf("工作器數量: %d\n", len(app.workers))
fmt.Printf("是否正在關閉: %v\n", app.isShutdown)
fmt.Printf("當前時間: %s\n", time.Now().Format("2006-01-02 15:04:05"))
for _, worker := range app.workers {
fmt.Printf(" 工作器: %s (ID: %d)\n", worker.name, worker.id)
}
}
func (app *Application) toggleDebugMode() {
fmt.Println("切換調試模式...")
// 這裏可以實現調試模式切換邏輯
fmt.Println("調試模式已切換")
}
func main() {
app := NewApplication()
// 添加一些工作器
app.AddWorker(1, "數據處理器")
app.AddWorker(2, "日誌處理器")
app.AddWorker(3, "監控處理器")
fmt.Println("可以使用以下命令測試不同信號:")
fmt.Println(" Ctrl+C - SIGINT (立即關閉)")
fmt.Printf(" kill -TERM %d - SIGTERM (優雅關閉)\n", os.Getpid())
fmt.Printf(" kill -HUP %d - SIGHUP (重新加載配置)\n", os.Getpid())
fmt.Printf(" kill -USR1 %d - SIGUSR1 (打印狀態)\n", os.Getpid())
fmt.Printf(" kill -USR2 %d - SIGUSR2 (切換調試模式)\n", os.Getpid())
app.Start()
}
使用 Context 進行信號處理
005.go
package main
import (
"context"
"fmt"
"net/http"
"os/signal"
"sync"
"syscall"
"time"
)
func main() {
fmt.Println("=== Context 信號處理演示 ===")
// 使用 signal.NotifyContext 創建可取消的上下文
ctx, stop := signal.NotifyContext(context.Background(),
syscall.SIGINT, syscall.SIGTERM)
defer stop()
var wg sync.WaitGroup
// 啓動多個工作器
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(workerID int) {
defer wg.Done()
runContextWorker(ctx, workerID)
}(i)
}
// 啓動 HTTP 服務器
wg.Add(1)
go func() {
defer wg.Done()
runContextHTTPServer(ctx)
}()
// 啓動定時任務
wg.Add(1)
go func() {
defer wg.Done()
runContextScheduler(ctx)
}()
fmt.Println("所有服務已啓動,按 Ctrl+C 或發送 SIGTERM 信號來停止")
// 等待上下文取消
<-ctx.Done()
fmt.Println("\n收到關閉信號,開始優雅關閉...")
// 等待所有 goroutine 完成
wg.Wait()
fmt.Println("所有服務已優雅關閉")
}
func runContextWorker(ctx context.Context, workerID int) {
fmt.Printf("工作器 %d 啓動\n", workerID)
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
fmt.Printf("工作器 %d 收到關閉信號: %v\n", workerID, ctx.Err())
// 模擬清理工作
cleanupTime := time.Duration(workerID) * time.Second
fmt.Printf("工作器 %d 開始清理工作,預計需要 %v\n", workerID, cleanupTime)
// 使用帶超時的上下文進行清理
cleanupCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
select {
case <-time.After(cleanupTime):
fmt.Printf("工作器 %d 清理工作完成\n", workerID)
case <-cleanupCtx.Done():
fmt.Printf("工作器 %d 清理工作超時,強制退出\n", workerID)
}
return
case <-ticker.C:
fmt.Printf("工作器 %d 正在處理任務... %s\n",
workerID, time.Now().Format("15:04:05"))
}
}
}
func runContextHTTPServer(ctx context.Context) {
server := &http.Server{
Addr: ":8081",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 檢查上下文是否已取消
select {
case <-ctx.Done():
http.Error(w, "服務正在關閉", http.StatusServiceUnavailable)
return
default:
}
fmt.Fprintf(w, "Hello from context server! Time: %s\n",
time.Now().Format("2006-01-02 15:04:05"))
}),
}
fmt.Println("HTTP 服務器啓動在 :8081")
// 在 goroutine 中啓動服務器
go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
fmt.Printf("HTTP 服務器錯誤: %v\n", err)
}
}()
// 等待上下文取消
<-ctx.Done()
fmt.Println("HTTP 服務器收到關閉信號")
// 創建關閉超時上下文
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := server.Shutdown(shutdownCtx); err != nil {
fmt.Printf("HTTP 服務器關閉錯誤: %v\n", err)
} else {
fmt.Println("HTTP 服務器優雅關閉完成")
}
}
func runContextScheduler(ctx context.Context) {
fmt.Println("定時調度器啓動")
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
jobCount := 0
for {
select {
case <-ctx.Done():
fmt.Printf("定時調度器收到關閉信號,已執行 %d 個任務\n", jobCount)
// 等待當前任務完成
fmt.Println("定時調度器等待當前任務完成...")
time.Sleep(1 * time.Second)
fmt.Println("定時調度器關閉完成")
return
case <-ticker.C:
jobCount++
fmt.Printf("定時調度器執行任務 #%d - %s\n",
jobCount, time.Now().Format("15:04:05"))
// 模擬任務處理
go func(id int) {
// 使用派生上下文來處理任務
taskCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
select {
case <-time.After(2 * time.Second):
fmt.Printf(" 任務 #%d 完成\n", id)
case <-taskCtx.Done():
fmt.Printf(" 任務 #%d 被取消: %v\n", id, taskCtx.Err())
}
}(jobCount)
}
}
}
信號處理的高級模式
package main
import (
"context"
"fmt"
"log"
"os"
"net/http"
"os/signal"
"sync"
"sync/atomic"
"syscall"
"time"
)
// SignalManager 管理應用程序的信號處理
type SignalManager struct {
handlers map[os.Signal][]SignalHandler
mu sync.RWMutex
shutdownCh chan struct{}
isShutdown int32
ctx context.Context
cancel context.CancelFunc
}
// SignalHandler 定義信號處理函數類型
type SignalHandler func(sig os.Signal) error
// NewSignalManager 創建新的信號管理器
func NewSignalManager() *SignalManager {
ctx, cancel := context.WithCancel(context.Background())
return &SignalManager{
handlers: make(map[os.Signal][]SignalHandler),
shutdownCh: make(chan struct{}),
ctx: ctx,
cancel: cancel,
}
}
// RegisterHandler 註冊信號處理器
func (sm *SignalManager) RegisterHandler(sig os.Signal, handler SignalHandler) {
sm.mu.Lock()
defer sm.mu.Unlock()
sm.handlers[sig] = append(sm.handlers[sig], handler)
}
// Start 啓動信號監聽
func (sm *SignalManager) Start() {
// 收集所有註冊的信號
var signals []os.Signal
sm.mu.RLock()
for sig := range sm.handlers {
signals = append(signals, sig)
}
sm.mu.RUnlock()
if len(signals) == 0 {
return
}
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, signals...)
go func() {
for {
select {
case sig := <-sigChan:
if atomic.LoadInt32(&sm.isShutdown) == 1 {
continue
}
fmt.Printf("收到信號: %v\n", sig)
sm.handleSignal(sig)
case <-sm.ctx.Done():
signal.Stop(sigChan)
return
}
}
}()
}
// handleSignal 處理接收到的信號
func (sm *SignalManager) handleSignal(sig os.Signal) {
sm.mu.RLock()
handlers := sm.handlers[sig]
sm.mu.RUnlock()
for _, handler := range handlers {
if err := handler(sig); err != nil {
log.Printf("信號處理器錯誤: %v", err)
}
}
}
// Shutdown 關閉信號管理器
func (sm *SignalManager) Shutdown() {
if atomic.CompareAndSwapInt32(&sm.isShutdown, 0, 1) {
close(sm.shutdownCh)
sm.cancel()
}
}
// Context 返回上下文
func (sm *SignalManager) Context() context.Context {
return sm.ctx
}
// ShutdownChannel 返回關閉通道
func (sm *SignalManager) ShutdownChannel() <-chan struct{} {
return sm.shutdownCh
}
// 應用程序服務接口
type Service interface {
Start(ctx context.Context) error
Stop(ctx context.Context) error
Name() string
}
// HTTP 服務實現
type HTTPService struct {
name string
port string
server *http.Server
}
func NewHTTPService(name, port string) *HTTPService {
return &HTTPService{
name: name,
port: port,
}
}
func (s *HTTPService) Name() string {
return s.name
}
func (s *HTTPService) Start(ctx context.Context) error {
s.server = &http.Server{
Addr: s.port,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from %s! Time: %s\n",
s.name, time.Now().Format("2006-01-02 15:04:05"))
}),
}
fmt.Printf("HTTP 服務 %s 啓動在 %s\n", s.name, s.port)
go func() {
if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Printf("HTTP 服務 %s 錯誤: %v\n", s.name, err)
}
}()
return nil
}
func (s *HTTPService) Stop(ctx context.Context) error {
if s.server == nil {
return nil
}
fmt.Printf("關閉 HTTP 服務 %s...\n", s.name)
shutdownCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
if err := s.server.Shutdown(shutdownCtx); err != nil {
return fmt.Errorf("HTTP 服務 %s 關閉失敗: %w", s.name, err)
}
fmt.Printf("HTTP 服務 %s 關閉完成\n", s.name)
return nil
}
// 工作器服務實現
type WorkerService struct {
name string
interval time.Duration
cancel context.CancelFunc
wg sync.WaitGroup
}
func NewWorkerService(name string, interval time.Duration) *WorkerService {
return &WorkerService{
name: name,
interval: interval,
}
}
func (s *WorkerService) Name() string {
return s.name
}
func (s *WorkerService) Start(ctx context.Context) error {
workerCtx, cancel := context.WithCancel(ctx)
s.cancel = cancel
s.wg.Add(1)
go func() {
defer s.wg.Done()
s.run(workerCtx)
}()
fmt.Printf("工作器服務 %s 啓動,間隔: %v\n", s.name, s.interval)
return nil
}
func (s *WorkerService) run(ctx context.Context) {
ticker := time.NewTicker(s.interval)
defer ticker.Stop()
count := 0
for {
select {
case <-ctx.Done():
fmt.Printf("工作器服務 %s 收到停止信號\n", s.name)
return
case <-ticker.C:
count++
fmt.Printf("工作器服務 %s 執行任務 #%d - %s\n",
s.name, count, time.Now().Format("15:04:05"))
}
}
}
func (s *WorkerService) Stop(ctx context.Context) error {
if s.cancel != nil {
s.cancel()
}
fmt.Printf("等待工作器服務 %s 停止...\n", s.name)
done := make(chan struct{})
go func() {
s.wg.Wait()
close(done)
}()
select {
case <-done:
fmt.Printf("工作器服務 %s 停止完成\n", s.name)
return nil
case <-ctx.Done():
return fmt.Errorf("工作器服務 %s 停止超時", s.name)
}
}
// 應用程序管理器
type Application struct {
services []Service
signalManager *SignalManager
mu sync.RWMutex
}
func NewApplication() *Application {
app := &Application{
services: make([]Service, 0),
signalManager: NewSignalManager(),
}
// 註冊信號處理器
app.registerSignalHandlers()
return app
}
func (app *Application) registerSignalHandlers() {
// SIGINT 處理器 - 立即關閉
app.signalManager.RegisterHandler(syscall.SIGINT, func(sig os.Signal) error {
fmt.Println("收到 SIGINT,開始立即關閉...")
go func() {
time.Sleep(100 * time.Millisecond) // 給日誌輸出一點時間
app.shutdown(5 * time.Second) // 較短的超時時間
}()
return nil
})
// SIGTERM 處理器 - 優雅關閉
app.signalManager.RegisterHandler(syscall.SIGTERM, func(sig os.Signal) error {
fmt.Println("收到 SIGTERM,開始優雅關閉...")
go func() {
time.Sleep(100 * time.Millisecond)
app.shutdown(30 * time.Second) // 較長的超時時間
}()
return nil
})
// SIGHUP 處理器 - 重新加載
app.signalManager.RegisterHandler(syscall.SIGHUP, func(sig os.Signal) error {
fmt.Println("收到 SIGHUP,重新加載配置...")
return app.reload()
})
// SIGUSR1 處理器 - 狀態報告
app.signalManager.RegisterHandler(syscall.SIGUSR1, func(sig os.Signal) error {
fmt.Println("收到 SIGUSR1,打印狀態信息...")
return app.printStatus()
})
}
func (app *Application) AddService(service Service) {
app.mu.Lock()
defer app.mu.Unlock()
app.services = append(app.services, service)
}
func (app *Application) Run() error {
fmt.Println("=== 高級信號處理應用程序 ===")
// 啓動信號管理器
app.signalManager.Start()
// 啓動所有服務
ctx := app.signalManager.Context()
for _, service := range app.services {
if err := service.Start(ctx); err != nil {
return fmt.Errorf("啓動服務 %s 失敗: %w", service.Name(), err)
}
}
fmt.Printf("所有服務已啓動,進程 PID: %d\n", os.Getpid())
fmt.Println("可用信號:")
fmt.Println(" Ctrl+C - SIGINT (立即關閉)")
fmt.Printf(" kill -TERM %d - SIGTERM (優雅關閉)\n", os.Getpid())
fmt.Printf(" kill -HUP %d - SIGHUP (重新加載)\n", os.Getpid())
fmt.Printf(" kill -USR1 %d - SIGUSR1 (狀態信息)\n", os.Getpid())
// 等待關閉信號
<-app.signalManager.ShutdownChannel()
fmt.Println("應用程序完全關閉")
return nil
}
func (app *Application) shutdown(timeout time.Duration) {
fmt.Printf("開始關閉所有服務,超時時間: %v\n", timeout)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
// 反向關閉服務
app.mu.RLock()
services := make([]Service, len(app.services))
copy(services, app.services)
app.mu.RUnlock()
for i := len(services) - 1; i >= 0; i-- {
service := services[i]
if err := service.Stop(ctx); err != nil {
log.Printf("關閉服務 %s 失敗: %v", service.Name(), err)
}
}
app.signalManager.Shutdown()
}
func (app *Application) reload() error {
fmt.Println("執行配置重新加載...")
// 這裏可以實現配置重新加載邏輯
time.Sleep(1 * time.Second) // 模擬重新加載時間
fmt.Println("配置重新加載完成")
return nil
}
func (app *Application) printStatus() error {
app.mu.RLock()
defer app.mu.RUnlock()
fmt.Println("=== 應用程序狀態 ===")
fmt.Printf("服務數量: %d\n", len(app.services))
fmt.Printf("當前時間: %s\n", time.Now().Format("2006-01-02 15:04:05"))
fmt.Printf("進程 PID: %d\n", os.Getpid())
for i, service := range app.services {
fmt.Printf(" 服務 %d: %s\n", i+1, service.Name())
}
return nil
}
func main() {
app := NewApplication()
// 添加服務
app.AddService(NewHTTPService("API服務", ":8080"))
app.AddService(NewHTTPService("管理服務", ":8081"))
app.AddService(NewWorkerService("數據處理器", 3*time.Second))
app.AddService(NewWorkerService("日誌處理器", 5*time.Second))
if err := app.Run(); err != nil {
log.Fatalf("應用程序運行失敗: %v", err)
}
}