From 7f49105b2314103535efbd58f3df0594a0ead848 Mon Sep 17 00:00:00 2001 From: zhaoyupeng Date: Thu, 10 Jul 2025 16:16:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20MustStop=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95=20feat:=20=E6=B7=BB=E5=8A=A0=20gin=20?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=89=A7=E8=A1=8C=20api=20=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/api.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tool/must.go | 35 ++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 api/api.go diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..add4303 --- /dev/null +++ b/api/api.go @@ -0,0 +1,60 @@ +package api + +import ( + "context" + "crypto/tls" + "errors" + "gitea.loveuer.com/yizhisec/packages/logger" + "github.com/gin-gonic/gin" + "net" + "net/http" +) + +type Api struct { + Address string + Name string + App *gin.Engine + TlsConfig *tls.Config +} + +func New(ctx context.Context, api *Api) (func(context.Context) error, error) { + var ( + err error + fn func(context.Context) error + ln net.Listener + ) + + if api == nil { + return fn, errors.New("api is nil") + } + + if api.TlsConfig != nil { + ln, err = tls.Listen("tcp", api.Address, api.TlsConfig) + } else { + ln, err = net.Listen("tcp", api.Address) + } + + if err != nil { + return fn, err + } + + svc := &http.Server{ + Handler: api.App, + } + + go func() { + logger.InfoCtx(ctx, "[%s] api svc running at: %s", api.Name, api.Address) + if err = svc.Serve(ln); err != nil { + if !errors.Is(err, http.ErrServerClosed) { + logger.ErrorCtx(ctx, "api svc run failed, err = %s", err.Error()) + } + } + }() + + fn = func(timeout context.Context) error { + logger.WarnCtx(ctx, "[%s] api svc shutdown...", api.Name) + return svc.Shutdown(timeout) + } + + return fn, nil +} diff --git a/tool/must.go b/tool/must.go index 20154a0..742463c 100644 --- a/tool/must.go +++ b/tool/must.go @@ -1,7 +1,9 @@ package tool import ( + "context" "gitea.loveuer.com/yizhisec/packages/logger" + "sync" ) func Must(errs ...error) { @@ -16,3 +18,36 @@ func MustWithData[T any](data T, err error) T { Must(err) return data } + +func MustStop(ctx context.Context, stopFns ...func(ctx context.Context) error) { + if len(stopFns) == 0 { + return + } + + ok := make(chan struct{}) + + wg := &sync.WaitGroup{} + wg.Add(len(stopFns)) + + for _, fn := range stopFns { + go func() { + defer wg.Done() + + if err := fn(ctx); err != nil { + logger.ErrorCtx(ctx, "stop function failed, err = %s", err.Error()) + } + }() + } + + go func() { + select { + case <-ctx.Done(): + logger.FatalCtx(ctx, "stop function timeout, force down") + case _, _ = <-ok: + return + } + }() + + wg.Wait() + close(ok) +}