Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update and rename main.go #15

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 54 additions & 15 deletions main.go → updated main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"bytes"
"context"
"encoding/json"
"io"
"loadbalancer/lib"
"log"
Expand All @@ -13,6 +14,8 @@ import (
"os/signal"
"syscall"
"time"

gomail "gopkg.in/gomail.v2"
)

type RetryType int
Expand All @@ -25,7 +28,7 @@ const (

var serverPool lib.ServerPool

// this function creates a log file if it does not already exist
// Initialize logger
func InitLogger() (*os.File, error) {
logFile, err := os.OpenFile("loadbalancer.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
Expand All @@ -36,43 +39,44 @@ func InitLogger() (*os.File, error) {
return logFile, nil
}

// this function logs details about incoming requests
// Log incoming requests
func LogRequest(r *http.Request) {
clientIp := r.RemoteAddr
method := r.Method
url := r.URL.String()
log.Printf("Received request from %s : %s, %s ", clientIp, method, url)
}

// this function logs which backend is selected
// Log backend selection
func LogBackendSelection(backendURL string) {
log.Printf("Routing request to backend: %s", backendURL)
}

// this function measures the time taken to process a request
// Track response time
func TrackresponseTime(start time.Time, backendURL string) {
duration := time.Since(start)
log.Printf("Request to backend %s took %v", backendURL, duration)
}

// this functions returns the retry count from the context
// Get retry count from context
func GetRetryFromContext(r *http.Request) int {
if retry, ok := r.Context().Value(Retry).(int); ok {
return retry
}
return 0
}

// this function returns the attempts from the context
// Get attempts from context
func GetAttemptsFromContext(r *http.Request) int {
if attempts, ok := r.Context().Value(Attempts).(int); ok {
return attempts
}
return 1
}

// Load balancer handler
func lb(w http.ResponseWriter, r *http.Request) {
//log the request
// Log the request
LogRequest(r)

peer := serverPool.GetNextPeer()
Expand All @@ -92,26 +96,59 @@ func lb(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Service not available", http.StatusServiceUnavailable)
}

func main() {
// Health check function
func healthCheck() {
for {
for _, backend := range serverPool.Backends {
resp, err := http.Get(backend.URL.String())
if err != nil || resp.StatusCode != http.StatusOK {
log.Printf("Server down: %s, sending alert.", backend.URL.String())
sendAlert(backend.URL.String())
serverPool.MarkDownTheServer(backend.URL, true) // Mark the server as down
} else {
serverPool.MarkDownTheServer(backend.URL, false) // Mark the server as up if it's responding
}
if resp != nil {
resp.Body.Close()
}
}
time.Sleep(30 * time.Second) // Check every 30 seconds
}
}

// Send alert function
func sendAlert(serverURL string) {
m := gomail.NewMessage()
m.SetHeader("From", "[email protected]") // Replace with your email
m.SetHeader("To", "[email protected]") // Replace with recipient email
m.SetHeader("Subject", "Alert: Server is down")
m.SetBody("text/plain", "The server at "+serverURL+" is unresponsive.")

//Initialize logger
d := gomail.NewDialer("smtp.example.com", 587, "[email protected]", "your-email-password") // Replace with your SMTP details

if err := d.DialAndSend(m); err != nil {
log.Printf("Failed to send alert: %v", err)
}
}

func main() {
// Initialize logger
logfile, err := InitLogger()
if err != nil {
log.Fatalf("Error initializing logger: %v", err)
}

defer logfile.Close()

// get file name from argument
// Get file name from argument
arg := os.Args
if len(arg) != 2 {
log.Fatal("usage go run main.go <config-file>'")
log.Fatal("usage: go run main.go <config-file>")
}

// declare slice for backend server
// Declare slice for backend servers
backendservers := []string{}

// read the config file and get the host and url.
// Read the config file and get the host and URL.
var config lib.Config
config, err = lib.ReadConfig(arg[1])
if err != nil {
Expand All @@ -129,7 +166,6 @@ func main() {
for _, backend := range backendservers {
log.Println("Load balancing to the backend server: ", backend)
be, err := url.Parse(backend)
log.Println(be)
if err != nil {
log.Println("Error parsing URL")
}
Expand Down Expand Up @@ -176,6 +212,9 @@ func main() {
})
}

// Start the health check in a separate goroutine
go healthCheck()

server := &http.Server{
Addr: ":8000",
WriteTimeout: 15 * time.Second,
Expand Down