支持服务优雅关闭,避免重启回复中断和面板缓存数据丢失 (#4258)
* feat: add graceful shutdown with configurable timeout * fix: flush quota dashboard cache on graceful shutdown Persist the in-memory CacheQuotaData aggregation to the quota_data table before process exit, so a restart no longer drops up to one DataExportInterval window of dashboard data (issue #5679).
This commit is contained in:
@@ -2,13 +2,17 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"embed"
|
"embed"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/QuantumNous/new-api/common"
|
"github.com/QuantumNous/new-api/common"
|
||||||
@@ -209,10 +213,34 @@ func main() {
|
|||||||
// Log startup success message
|
// Log startup success message
|
||||||
common.LogStartupSuccess(startTime, port)
|
common.LogStartupSuccess(startTime, port)
|
||||||
|
|
||||||
err = server.Run(":" + port)
|
srv := &http.Server{
|
||||||
if err != nil {
|
Addr: ":" + port,
|
||||||
common.FatalLog("failed to start HTTP server: " + err.Error())
|
Handler: server,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
common.FatalLog("failed to start HTTP server: " + err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
quit := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
sig := <-quit
|
||||||
|
common.SysLog(fmt.Sprintf("received signal: %v, shutting down...", sig))
|
||||||
|
|
||||||
|
// SSE streams may run for minutes; give them time to finish before forced exit
|
||||||
|
shutdownTimeout := time.Duration(common.GetEnvOrDefault("SHUTDOWN_TIMEOUT_SECONDS", 120)) * time.Second
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
||||||
|
defer cancel()
|
||||||
|
if err := srv.Shutdown(ctx); err != nil {
|
||||||
|
common.SysError(fmt.Sprintf("server forced to shutdown: %v", err))
|
||||||
|
}
|
||||||
|
// 内存中的看板数据保存入库,避免重启丢失未落库数据 (issue #5679)
|
||||||
|
if common.DataExportEnabled {
|
||||||
|
model.SaveQuotaDataCache()
|
||||||
|
}
|
||||||
|
common.SysLog("server exited")
|
||||||
}
|
}
|
||||||
|
|
||||||
func InjectUmamiAnalytics() {
|
func InjectUmamiAnalytics() {
|
||||||
|
|||||||
Reference in New Issue
Block a user