So I'm building a simple load balancer and I'm facing this problem only in docker environment. Without docker it works normally and healthcheck enables all 3 of my servers and then weighted round robin works fine. But in docker environment i can't figure out what is happening.
This is my Healthcheck function:
func (lb *LoadBalancer) HealthCheckPeriodically() {
for {
lb.mutex.Lock()
for _, server := range lb.servers {
resp, err := http.Get(server.URL)
log.Printf("server.URL: %s ", server.URL)
if err != nil {
log.Printf("Server %s is down\n", server.Name)
lb.activeServers[server.URL] = false
} else {
log.Printf("Server %s is up\n", server.Name)
lb.activeServers[server.URL] = true
}
if resp != nil {
resp.Body.Close()
}
}
lb.mutex.Unlock()
time.Sleep(5 * time.Second)
}
}
Here is my round robin function:
func (lb *LoadBalancer) chooseServerWeightedRoundRobin() *Server {
var selected *Server
totalWeight := 0
for _, server := range lb.servers {
if lb.activeServers[server.URL] {
totalWeight += server.Weight
server.Current += server.Weight
if selected == nil || server.Current > selected.Current {
selected = server
}
}
}
if selected != nil {
selected.Current -= totalWeight
if selected.Current < 0 {
selected.Current = 0
}
}
return selected
}
So this is the route I'm trying to reach:
http.HandleFunc("/roundRobin", lb.handleRequest)
And I get the message: No active servers available
Here is also handleRequest function:
func (lb *LoadBalancer) handleRequest(w http.ResponseWriter, r *http.Request) {
lb.mutex.Lock()
defer lb.mutex.Unlock()
if len(lb.servers) == 0 {
http.Error(w, "No servers available", http.StatusServiceUnavailable)
return
}
selected := lb.chooseServerWeightedRoundRobin()
if selected == nil {
http.Error(w, "No active servers available", http.StatusServiceUnavailable)
return
}
proxyURL, err := url.Parse(selected.URL)
if err != nil {
log.Printf("Failed to parse target URL: %s\n", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
proxy := httputil.NewSingleHostReverseProxy(proxyURL)
proxy.ServeHTTP(w, r)
}
And in load balancer log I'm getting these messages:
load-balancer_1 | 2023/07/01 00:21:32 server.URL: http://localhost:8001
load-balancer_1 | 2023/07/01 00:21:32 Server Server 1 is down
load-balancer_1 | 2023/07/01 00:21:32 server.URL: http://localhost:8002
load-balancer_1 | 2023/07/01 00:21:32 Server Server 2 is down
load-balancer_1 | 2023/07/01 00:21:32 server.URL: http://localhost:8003
load-balancer_1 | 2023/07/01 00:21:32 Server Server 3 is down
Also here is Dockerfile:
FROM golang:1.16-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o loadbalancer loadbalancer.go
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/loadbalancer .
EXPOSE 8000
CMD ["./loadbalancer"]