Commit 7b4601c0 authored by Ali Saeed's avatar Ali Saeed

Load Balancer Homework

parents
{
"healthCheckInterval": "5s",
"servers": [
{
"Name": "Server1",
"URL": "http://192.168.181.1:8081",
"ActiveConnections": 0,
"Mutex": {},
"Healthy": true
},
{
"Name": "Server2",
"URL": "http://192.168.181.1:8082",
"ActiveConnections": 0,
"Mutex": {},
"Healthy": true
},
{
"Name": "Server3",
"URL": "http://192.168.181.1:8083",
"ActiveConnections": 0,
"Mutex": {},
"Healthy": true
}
],
"listenPort": ":9090"
}
package main
import (
"encoding/json"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"net/url"
"sync"
"time"
"os"
)
type Server struct {
Name string
URL string
ActiveConnections int
Mutex sync.Mutex
Healthy bool
}
type Config struct {
HealthCheckInterval string `json:"healthCheckInterval"`
Servers []Server `json:"servers"`
ListenPort string `json:"listenPort"`
}
func loadConfig(file string) (Config, error) {
var config Config
bytes, err := ioutil.ReadFile(file)
if err != nil {
return config, err
}
err = json.Unmarshal(bytes, &config)
if err != nil {
return config, err
}
return config, nil
}
func nextServerLeastActive(servers []*Server) *Server {
leastActiveConnections := -1
leastActiveServer := servers[0]
for _, server := range servers {
server.Mutex.Lock()
if (server.ActiveConnections < leastActiveConnections || leastActiveConnections == -1) && server.Healthy {
leastActiveConnections = server.ActiveConnections
leastActiveServer = server
}
server.Mutex.Unlock()
}
return leastActiveServer
}
func (s *Server) Proxy() *httputil.ReverseProxy {
urlObj, _ := url.Parse(s.URL)
return httputil.NewSingleHostReverseProxy(urlObj)
}
func main() {
logFile, err := os.OpenFile("logfile.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Error opening log file: %s", err.Error())
}
defer logFile.Close()
log.SetOutput(logFile)
config, err := loadConfig("config.json")
if err != nil {
log.Fatalf("Error loading configuration: %s", err.Error())
}
healthCheckInterval, err := time.ParseDuration(config.HealthCheckInterval)
if err != nil {
log.Fatalf("Invalid health check interval: %s", err.Error())
}
var servers []*Server
for _, server := range config.Servers {
servers = append(servers, &Server{
Name: server.Name,
URL: server.URL,
ActiveConnections: 0,
Mutex: sync.Mutex{},
Healthy: true,
})
}
for _, server := range servers {
go func(s *Server) {
for range time.Tick(healthCheckInterval) {
res, err := http.Get(s.URL)
if err != nil || res.StatusCode >= 500 {
s.Healthy = false
} else {
s.Healthy = true
}
}
}(server)
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
log.Println("Received request:", r.Method, r.URL.Path, "Server:", r.Host)
server := nextServerLeastActive(servers)
server.Mutex.Lock()
server.ActiveConnections++
server.Mutex.Unlock()
server.Proxy().ServeHTTP(w, r)
server.Mutex.Lock()
time.Sleep(15 * time.Second)
server.ActiveConnections--
server.Mutex.Unlock()
log.Println("Request completed:", r.Method, r.URL.Path, "Server:", r.Host, "Server URL:", server.URL)
})
log.Println("Starting server on port", config.ListenPort)
err = http.ListenAndServe(config.ListenPort, nil)
if err != nil {
log.Fatalf("Error starting server: %s\n", err)
}
}
\ No newline at end of file
2024/03/02 17:06:23 Starting server on port :9090
2024/03/02 17:06:26 Received request: GET / Server: 192.168.181.136:9090
2024/03/02 17:06:46 Request completed: GET / Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8081
2024/03/02 17:06:46 Received request: GET / Server: 192.168.181.136:9090
2024/03/02 17:06:47 Received request: GET /favicon.ico Server: 192.168.181.136:9090
2024/03/02 17:06:50 Received request: GET / Server: 192.168.181.136:9090
2024/03/02 17:07:07 Request completed: GET / Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8081
2024/03/02 17:07:07 Request completed: GET /favicon.ico Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8082
2024/03/02 17:07:07 Received request: GET / Server: 192.168.181.136:9090
2024/03/02 17:07:08 Received request: GET /favicon.ico Server: 192.168.181.136:9090
2024/03/02 17:07:22 Request completed: GET / Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8081
2024/03/02 17:07:34 Received request: GET / Server: 192.168.181.136:9090
2024/03/02 17:07:43 Received request: GET /favicon.ico Server: 192.168.181.136:9090
2024/03/02 17:07:43 Request completed: GET / Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8081
2024/03/02 17:07:43 Request completed: GET /favicon.ico Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8082
2024/03/02 17:07:43 Received request: GET / Server: 192.168.181.136:9090
2024/03/02 17:07:44 Received request: GET /favicon.ico Server: 192.168.181.136:9090
2024/03/02 17:08:07 Request completed: GET / Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8082
2024/03/02 17:08:07 Request completed: GET /favicon.ico Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8081
2024/03/02 17:08:07 Received request: GET / Server: 192.168.181.136:9090
2024/03/02 17:08:22 Request completed: GET /favicon.ico Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8082
2024/03/02 17:08:22 Request completed: GET / Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8081
2024/03/02 17:08:22 Received request: GET /favicon.ico Server: 192.168.181.136:9090
2024/03/02 17:08:42 Request completed: GET /favicon.ico Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8082
2024/03/02 17:08:42 Request completed: GET / Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8081
2024/03/02 17:08:42 Received request: GET /favicon.ico Server: 192.168.181.136:9090
2024/03/02 17:09:02 Request completed: GET /favicon.ico Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8081
2024/03/02 17:09:02 Received request: GET /favicon.ico Server: 192.168.181.136:9090
2024/03/02 17:09:22 Request completed: GET /favicon.ico Server: 192.168.181.136:9090 Server URL: http://192.168.181.1:8081
File added
# Default ignored files
/shelf/
/workspace.xml
<component name="ArtifactManager">
<artifact type="jar" name="Simple_Web_Service:jar">
<output-path>$PROJECT_DIR$/out/artifacts/Simple_Web_Service_jar</output-path>
<root id="archive" name="Simple_Web_Service.jar">
<element id="module-output" name="Simple_Web_Service" />
</root>
</artifact>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="Simple_Web_Service" />
</profile>
</annotationProcessing>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17 (2)" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Simple_Web_Service</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
\ No newline at end of file
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class WebServer {
public static void main(String[] args) throws IOException {
if (args.length != 1) {
System.err.println("Usage: java -jar server.jar <port>");
System.exit(1);
}
int port = Integer.parseInt(args[0]);
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
server.createContext("/", new MainHandler(port));
server.start();
System.out.println("Starting web service on port " + port);
}
static class MainHandler implements HttpHandler {
private int port;
public MainHandler(int port) {
this.port = port;
}
@Override
public void handle(HttpExchange exchange) throws IOException {
String response = "<html><body><h1>Hello, World!</h1>" +
"<p>Server Address: " + exchange.getLocalAddress().getHostName() + "</p>" +
"<p>Server Port: " + port + "</p></body></html>";
exchange.sendResponseHeaders(200, response.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
}
Manifest-Version: 1.0
Main-Class: WebServer
Manifest-Version: 1.0
Main-Class: WebServer
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment