mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-20 23:41:23 +02:00
improved idlewatcher support for API-like services, fixed idlewaker proxying to zero port
This commit is contained in:
@@ -3,6 +3,7 @@ package idlewatcher
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -22,6 +23,20 @@ func NewWaker(w *watcher, rp *gphttp.ReverseProxy) *Waker {
|
||||
if w.NoTLSVerify {
|
||||
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
orig := rp.ServeHTTP
|
||||
// workaround for stopped containers port become zero
|
||||
rp.ServeHTTP = func(rw http.ResponseWriter, r *http.Request) {
|
||||
if rp.TargetURL.Port() == "0" {
|
||||
port, ok := portHistoryMap.Load(w.Alias)
|
||||
if !ok {
|
||||
w.l.Errorf("port history not found for %s", w.Alias)
|
||||
http.Error(rw, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
rp.TargetURL.Host = fmt.Sprintf("%s:%v", rp.TargetURL.Hostname(), port)
|
||||
}
|
||||
orig(rw, r)
|
||||
}
|
||||
return &Waker{
|
||||
watcher: w,
|
||||
client: &http.Client{
|
||||
@@ -37,9 +52,10 @@ func (w *Waker) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (w *Waker) wake(next http.HandlerFunc, rw http.ResponseWriter, r *http.Request) {
|
||||
w.resetIdleTimer()
|
||||
|
||||
// pass through if container is ready
|
||||
if w.ready.Load() {
|
||||
w.resetIdleTimer()
|
||||
next(rw, r)
|
||||
return
|
||||
}
|
||||
@@ -48,14 +64,10 @@ func (w *Waker) wake(next http.HandlerFunc, rw http.ResponseWriter, r *http.Requ
|
||||
defer cancel()
|
||||
|
||||
accept := gphttp.GetAccept(r.Header)
|
||||
acceptHTML := accept.AcceptHTML() || accept.IsEmpty()
|
||||
acceptHTML := r.Method == http.MethodGet && accept.AcceptHTML()
|
||||
|
||||
if !acceptHTML {
|
||||
w.l.Debugf("Accept %v", accept)
|
||||
}
|
||||
|
||||
isCheckRedirect := r.Header.Get(headerCheckRedirect) != "" && acceptHTML
|
||||
if !isCheckRedirect {
|
||||
isCheckRedirect := r.Header.Get(headerCheckRedirect) != ""
|
||||
if !isCheckRedirect && acceptHTML {
|
||||
// Send a loading response to the client
|
||||
body := w.makeRespBody("%s waking up...", w.ContainerName)
|
||||
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
@@ -106,10 +118,10 @@ func (w *Waker) wake(next http.HandlerFunc, rw http.ResponseWriter, r *http.Requ
|
||||
return
|
||||
}
|
||||
|
||||
// we don't care about the response
|
||||
_, err = w.client.Do(wakeReq)
|
||||
if err == nil {
|
||||
wakeResp, err := w.client.Do(wakeReq)
|
||||
if err == nil && wakeResp.StatusCode != http.StatusServiceUnavailable {
|
||||
w.ready.Store(true)
|
||||
w.l.Debug("awaken")
|
||||
if isCheckRedirect {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
} else {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
P "github.com/yusing/go-proxy/internal/proxy"
|
||||
PT "github.com/yusing/go-proxy/internal/proxy/fields"
|
||||
F "github.com/yusing/go-proxy/internal/utils/functional"
|
||||
W "github.com/yusing/go-proxy/internal/watcher"
|
||||
)
|
||||
|
||||
@@ -45,9 +46,11 @@ var (
|
||||
mainLoopCancel context.CancelFunc
|
||||
mainLoopWg sync.WaitGroup
|
||||
|
||||
watcherMap = make(map[string]*watcher)
|
||||
watcherMap = F.NewMapOf[string, *watcher]()
|
||||
watcherMapMu sync.Mutex
|
||||
|
||||
portHistoryMap = F.NewMapOf[PT.Alias, string]()
|
||||
|
||||
newWatcherCh = make(chan *watcher)
|
||||
|
||||
logger = logrus.WithField("module", "idle_watcher")
|
||||
@@ -65,7 +68,11 @@ func Register(entry *P.ReverseProxyEntry) (*watcher, E.NestedError) {
|
||||
|
||||
key := entry.ContainerID
|
||||
|
||||
if w, ok := watcherMap[key]; ok {
|
||||
if entry.URL.Port() != "0" {
|
||||
portHistoryMap.Store(entry.Alias, entry.URL.Port())
|
||||
}
|
||||
|
||||
if w, ok := watcherMap.Load(key); ok {
|
||||
w.refCount.Add(1)
|
||||
w.ReverseProxyEntry = entry
|
||||
return w, nil
|
||||
@@ -88,7 +95,7 @@ func Register(entry *P.ReverseProxyEntry) (*watcher, E.NestedError) {
|
||||
w.refCount.Add(1)
|
||||
w.stopByMethod = w.getStopCallback()
|
||||
|
||||
watcherMap[key] = w
|
||||
watcherMap.Store(key, w)
|
||||
|
||||
go func() {
|
||||
newWatcherCh <- w
|
||||
@@ -118,7 +125,7 @@ func Start() {
|
||||
w.watchUntilCancel()
|
||||
w.refCount.Wait() // wait for 0 ref count
|
||||
|
||||
delete(watcherMap, w.ContainerID)
|
||||
watcherMap.Delete(w.ContainerID)
|
||||
w.l.Debug("unregistered")
|
||||
mainLoopWg.Done()
|
||||
}()
|
||||
|
||||
Reference in New Issue
Block a user