mirror of
https://github.com/fatedier/frp.git
synced 2026-10-16 04:55:56 +08:00
fix: synchronize service startup and shutdown (#5560)
This commit is contained in:
+41
-9
@@ -25,6 +25,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fatedier/golib/crypto"
|
||||
@@ -120,6 +121,9 @@ type Service struct {
|
||||
|
||||
// web server for dashboard UI and apis
|
||||
webServer *httppkg.Server
|
||||
// HTTP vhost resources are started and owned by NewService.
|
||||
httpVhostServer *http.Server
|
||||
httpVhostListener net.Listener
|
||||
|
||||
sshTunnelGateway *ssh.Gateway
|
||||
|
||||
@@ -133,7 +137,10 @@ type Service struct {
|
||||
// service context
|
||||
ctx context.Context
|
||||
// call cancel to stop service
|
||||
cancel context.CancelFunc
|
||||
cancel context.CancelFunc
|
||||
lifecycleMu sync.Mutex
|
||||
closed bool
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func NewService(cfg *v1.ServerConfig) (*Service, error) {
|
||||
@@ -319,6 +326,8 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) {
|
||||
return nil, fmt.Errorf("create vhost http listener error, %v", err)
|
||||
}
|
||||
}
|
||||
svr.httpVhostServer = server
|
||||
svr.httpVhostListener = l
|
||||
go func() {
|
||||
_ = server.Serve(l)
|
||||
}()
|
||||
@@ -365,8 +374,22 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) {
|
||||
|
||||
func (svr *Service) Run(ctx context.Context) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
svr.lifecycleMu.Lock()
|
||||
if svr.closed {
|
||||
svr.lifecycleMu.Unlock()
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
svr.ctx = ctx
|
||||
svr.cancel = cancel
|
||||
svr.lifecycleMu.Unlock()
|
||||
defer svr.Close()
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
// Cancellation must unblock the synchronous main listener's Accept.
|
||||
stopClose := context.AfterFunc(ctx, func() { _ = svr.Close() })
|
||||
defer stopClose()
|
||||
|
||||
// run dashboard web server.
|
||||
if svr.webServer != nil {
|
||||
@@ -400,13 +423,21 @@ func (svr *Service) Run(ctx context.Context) {
|
||||
svr.HandleListener(svr.listener, false)
|
||||
|
||||
<-svr.ctx.Done()
|
||||
// service context may not be canceled by svr.Close(), we should call it here to release resources
|
||||
if svr.listener != nil {
|
||||
svr.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (svr *Service) Close() error {
|
||||
svr.lifecycleMu.Lock()
|
||||
svr.closed = true
|
||||
cancel := svr.cancel
|
||||
svr.lifecycleMu.Unlock()
|
||||
if cancel != nil {
|
||||
cancel()
|
||||
}
|
||||
svr.closeOnce.Do(svr.closeResources)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svr *Service) closeResources() {
|
||||
if svr.kcpListener != nil {
|
||||
svr.kcpListener.Close()
|
||||
}
|
||||
@@ -428,16 +459,17 @@ func (svr *Service) Close() error {
|
||||
if svr.webServer != nil {
|
||||
svr.webServer.Close()
|
||||
}
|
||||
if svr.httpVhostServer != nil {
|
||||
svr.httpVhostServer.Close()
|
||||
// Close even if Serve has not registered its listener yet.
|
||||
svr.httpVhostListener.Close()
|
||||
}
|
||||
if svr.sshTunnelGateway != nil {
|
||||
svr.sshTunnelGateway.Close()
|
||||
}
|
||||
svr.rc.Close()
|
||||
svr.muxer.Close()
|
||||
svr.ctlManager.Close()
|
||||
if svr.cancel != nil {
|
||||
svr.cancel()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svr *Service) handleConnection(ctx context.Context, conn net.Conn, internal bool) {
|
||||
|
||||
Reference in New Issue
Block a user