Add more documentation, cleanup rate limit code

This commit is contained in:
Pablu23
2024-11-06 17:39:42 +01:00
parent c0b711a992
commit 3bf932363e
3 changed files with 38 additions and 18 deletions

View File

@@ -7,7 +7,7 @@ server:
logging: logging:
level: info level: debug
# Pretty print for human consumption otherwise json # Pretty print for human consumption otherwise json
pretty: true pretty: true
# Log incoming requests # Log incoming requests
@@ -25,11 +25,11 @@ rateLimit:
# How many requests per ip adress are allowed # How many requests per ip adress are allowed
bucketSize: 50 bucketSize: 50
# How many requests per ip address are refilled # How many requests per ip address are refilled
refillSize: 10 refillSize: 50
# How often requests per ip address are refilled # How often requests per ip address are refilled
refillTime: 1m refillTime: 30s
# How often Ip Addresses get cleaned up (only ip addresses with max allowed requests are cleaned up) # How often Ip Addresses get cleaned up (only ip addresses with max allowed requests are cleaned up)
cleanupTime: 5m cleanupTime: 45s
hosts: hosts:

View File

@@ -45,13 +45,13 @@ func (l *Limiter) Manage() {
for { for {
select { select {
case ip := <-l.rateChannel: case ip := <-l.rateChannel:
if l.AddIfExists(ip) {
break
}
l.rwLock.Lock() l.rwLock.Lock()
if counter, ok := l.currentBuckets[ip]; ok {
counter.Add(1)
} else {
counter := &atomic.Int64{} counter := &atomic.Int64{}
l.currentBuckets[ip] = counter l.currentBuckets[ip] = counter
}
l.rwLock.Unlock() l.rwLock.Unlock()
case <-l.refillTicker.C: case <-l.refillTicker.C:
l.rwLock.RLock() l.rwLock.RLock()
@@ -66,6 +66,7 @@ func (l *Limiter) Manage() {
l.rwLock.RUnlock() l.rwLock.RUnlock()
log.Trace().Msg("Refreshed Limits") log.Trace().Msg("Refreshed Limits")
case <-l.cleanupTicker.C: case <-l.cleanupTicker.C:
start := time.Now()
l.rwLock.Lock() l.rwLock.Lock()
deletedBuckets := 0 deletedBuckets := 0
for ip := range l.currentBuckets { for ip := range l.currentBuckets {
@@ -75,10 +76,22 @@ func (l *Limiter) Manage() {
} }
} }
l.rwLock.Unlock() l.rwLock.Unlock()
log.Debug().Int("deleted_buckets", deletedBuckets).Msg("Cleaned up Buckets") duration := time.Since(start)
log.Debug().Str("duration", duration.String()).Int("deleted_buckets", deletedBuckets).Msg("Cleaned up Buckets")
}
} }
} }
// Adds one if ip already exists and returns true
// If ip doesnt yet exist only returns false
func (l *Limiter) AddIfExists(ip string) bool {
l.rwLock.RLock()
defer l.rwLock.RUnlock()
if counter, ok := l.currentBuckets[ip]; ok {
counter.Add(1)
return true
}
return false
} }
func (l *Limiter) RateLimiter(next http.Handler) http.Handler { func (l *Limiter) RateLimiter(next http.Handler) http.Handler {

View File

@@ -62,7 +62,14 @@ func (router *Router) Healthz(w http.ResponseWriter, r *http.Request) {
} }
healthy := true healthy := true
res, err := router.client.Get(fmt.Sprintf("http://localhost:%d/healthz", host.Port)) var url string
if host.Secure {
url = fmt.Sprintf("https://%s:%d/healthz", host.Remote, host.Port)
} else {
url = fmt.Sprintf("http://%s:%d/healthz", host.Remote, host.Port)
}
res, err := router.client.Get(url)
if err != nil { if err != nil {
log.Warn().Err(err).Int("port", host.Port).Msg("Unhealthy") log.Warn().Err(err).Int("port", host.Port).Msg("Unhealthy")
healthy = false healthy = false
@@ -89,7 +96,7 @@ func (router *Router) Healthz(w http.ResponseWriter, r *http.Request) {
} }
func (router *Router) Route(w http.ResponseWriter, r *http.Request) { func (router *Router) Route(w http.ResponseWriter, r *http.Request) {
port, ok := router.domains.Get(r.Host) host, ok := router.domains.Get(r.Host)
if !ok { if !ok {
log.Warn().Str("host", r.Host).Msg("Could not find Host") log.Warn().Str("host", r.Host).Msg("Could not find Host")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
@@ -102,15 +109,15 @@ func (router *Router) Route(w http.ResponseWriter, r *http.Request) {
subUrlPath := r.URL.RequestURI() subUrlPath := r.URL.RequestURI()
var url string var url string
if port.Secure { if host.Secure {
url = fmt.Sprintf("https://%s:%d%s", port.Remote, port.Port, subUrlPath) url = fmt.Sprintf("https://%s:%d%s", host.Remote, host.Port, subUrlPath)
} else { } else {
url = fmt.Sprintf("http://%s:%d%s", port.Remote, port.Port, subUrlPath) url = fmt.Sprintf("http://%s:%d%s", host.Remote, host.Port, subUrlPath)
} }
req, err := http.NewRequest(r.Method, url, r.Body) req, err := http.NewRequest(r.Method, url, r.Body)
if err != nil { if err != nil {
log.Error().Err(err).Str("remote", port.Remote).Str("path", subUrlPath).Int("port", port.Port).Msg("Could not create request") log.Error().Err(err).Bool("secure", host.Secure).Str("remote", host.Remote).Str("path", subUrlPath).Int("port", host.Port).Msg("Could not create request")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
@@ -132,7 +139,7 @@ func (router *Router) Route(w http.ResponseWriter, r *http.Request) {
res, err := router.client.Do(req) res, err := router.client.Do(req)
if err != nil { if err != nil {
log.Error().Err(err).Str("remote", port.Remote).Str("path", subUrlPath).Int("port", port.Port).Msg("Could not complete request") log.Error().Err(err).Str("remote", host.Remote).Str("path", subUrlPath).Int("port", host.Port).Msg("Could not complete request")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }