-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
283 lines (225 loc) · 8.48 KB
/
main.go
File metadata and controls
283 lines (225 loc) · 8.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
package main
import (
"fmt"
"github.com/ayushs-2k4/go-load-balancer/loadbalancer"
"github.com/kontesthq/go-consul-service-manager/consulservicemanager"
"io"
"kontest-api/database"
"kontest-api/middleware"
"kontest-api/routes"
"kontest-api/utils"
"log/slog"
"net/http"
"os"
"path/filepath"
"strconv"
"time"
)
var (
applicationHost = "localhost" // Default value for local development
applicationPort = 5151 // Default value for local development
serviceName = "KONTEST-API" // Service name for Service Registry
consulHost = "localhost" // Default value for local development
consulPort = 5150 // Port as a constant (can be constant if it won't change)
dbHost = "localhost"
dbPort = "5432"
dbName = "kontest"
dbUser = "ayushsinghal"
dbPassword = ""
isSSLModeEnabled = false
)
func initializeVariables() {
// Get the hostname of the machine
hostname, err := os.Hostname()
if err != nil {
slog.Error("Error fetching hostname", slog.String("error", err.Error()))
os.Exit(1)
}
// Attempt to read the KONTEST_API_SERVER_HOST environment variable
if host := os.Getenv("KONTEST_API_SERVER_HOST"); host != "" {
applicationHost = host // Override with the environment variable if set
} else {
applicationHost = hostname // Use the machine's hostname if the env var is not set
}
// Attempt to read the KONTEST_API_SERVER_PORT environment variable
if port := os.Getenv("KONTEST_API_SERVER_PORT"); port != "" {
parsedPort, err := strconv.Atoi(port)
if err != nil {
slog.Error("Invalid port value", slog.String("error", err.Error()), slog.String("port", port))
os.Exit(1) // Exit the program with a non-zero status code
}
applicationPort = parsedPort // Override with the environment variable if set
slog.Info("Application port set from environment variable", slog.Int("applicationPort", applicationPort))
}
// Attempt to read the CONSUL_ADDRESS environment variable
if host := os.Getenv("CONSUL_HOST"); host != "" {
consulHost = host // Override with the environment variable if set
}
// Attempt to read the CONSUL_PORT environment variable
if port := os.Getenv("CONSUL_PORT"); port != "" {
if portInt, err := strconv.Atoi(port); err == nil {
consulPort = portInt // Override with the environment variable if set and valid
}
}
// Attempt to read the DB_HOST environment variable
if host := os.Getenv("DB_HOST"); host != "" {
dbHost = host // Override with the environment variable if set
}
// Attempt to read the DB_PORT environment variable
if port := os.Getenv("DB_PORT"); port != "" {
dbPort = port // Override with the environment variable if set
}
// Attempt to read the DB_NAME environment variable
if name := os.Getenv("DB_NAME"); name != "" {
dbName = name // Override with the environment variable if set
}
// Attempt to read the DB_USER environment variable
if user := os.Getenv("DB_USER"); user != "" {
dbUser = user // Override with the environment variable if set
}
// Attempt to read the DB_PASSWORD environment variable
if password := os.Getenv("DB_PASSWORD"); password != "" {
dbPassword = password // Override with the environment variable if set
}
// Attempt to read the DB_SSL_MODE environment variable
if sslMode := os.Getenv("DB_SSL_MODE"); sslMode != "" {
isSSLModeEnabled = sslMode == "enable"
}
}
func setupLogging() *os.File {
LOG_FILE := os.Getenv("LOG_FILE")
if LOG_FILE == "" {
LOG_FILE = "tmp/logs/logs.log"
}
// Get the directory from the log file path
logDir := filepath.Dir(LOG_FILE)
// Create the directory if it doesn't exist
if err := os.MkdirAll(logDir, 0755); err != nil {
slog.Error("Failed to create log directory", slog.String("error", err.Error()))
os.Exit(1)
}
handlerOptions := &slog.HandlerOptions{
AddSource: true,
}
// Open or create a log file
logFile, err := os.OpenFile(LOG_FILE, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
// Handle error if the log file cannot be opened or created
slog.Error("Failed to open log file", slog.String("error", err.Error()))
os.Exit(1)
}
w := io.MultiWriter(os.Stdout, logFile)
// Configure slog to output JSON
slog.SetDefault(slog.New(slog.NewJSONHandler(w, handlerOptions)))
// Return the log file to close it in the main function
return logFile
}
func main() {
// Set up logging and capture the log file
logFile := setupLogging()
// Ensure the log file is closed when the program exits
defer logFile.Close()
// Log server restart with a timestamp
slog.Info("Server restarted", slog.Time("time", time.Now()))
initializeVariables()
consulService := consulservicemanager.NewConsulService(consulHost, consulPort)
consulService.Start(applicationHost, applicationPort, serviceName, []string{})
//checkingLoadBalancer()
//checkLoadBalancerUserStatsService()
database.InitalizeDatabase(dbPort, dbHost, dbUser, dbPassword, dbName, map[bool]string{true: "enable", false: "disable"}[isSSLModeEnabled])
utils.InitializeDependencies()
router := http.NewServeMux()
routes.RegisterRoutes(router)
stack := middleware.CreateStack(
middleware.Logging,
)
server := http.Server{
Addr: ":" + strconv.Itoa(applicationPort), // Use the field name Addr for the address
Handler: stack(router), // Use the field name Handler for the router
}
slog.Info("Server listening", slog.Int("port", applicationPort))
err := server.ListenAndServe()
if err != nil {
slog.Error("Failed to start server", slog.String("error", err.Error()))
os.Exit(1)
}
}
func checkingLoadBalancer() {
lb, err := loadbalancer.GetLoadBalancer(serviceName, consulHost, consulPort)
if err != nil {
slog.Error("Failed to create load balancer", slog.String("error", err.Error()))
os.Exit(1)
}
instance, err := lb.ChooseInstance()
if err != nil || instance == nil {
slog.Error("Failed to choose instance", slog.String("error", err.Error()))
os.Exit(1)
}
slog.Info("Chosen instance", slog.String("address", instance.Address), slog.Int("port", instance.Port))
url := fmt.Sprintf("http://%s:%d/kontests?page=1&per_page=10", instance.Address, instance.Port)
client := &http.Client{
Timeout: 5 * time.Second,
}
go func() {
time.Sleep(5 * time.Second)
resp, err := client.Get(url)
if err != nil {
slog.Error("Failed to make HTTP request", slog.String("error", err.Error()))
os.Exit(1)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
slog.Error("Failed to read response", slog.String("error", err.Error()))
os.Exit(1)
}
slog.Info("Response from instance", slog.String("response", string(body)))
}()
slog.Info("Main thread is continuing execution...")
}
func checkLoadBalancerUserStatsService() {
lb, err := loadbalancer.GetLoadBalancer("KONTEST-USER-STATS-SERVICE", consulHost, consulPort)
if err != nil {
slog.Error("Failed to create load balancer", slog.String("error", err.Error()))
os.Exit(1) // Exit with an error
}
// Choose a random instance
instance, err := lb.ChooseInstance()
if err != nil || instance == nil {
slog.Error("Failed to choose instance", slog.String("error", err.Error()))
os.Exit(1) // Exit with an error
}
// Log the instance's address
slog.Info("Instance chosen", slog.String("address", instance.Address), slog.Int("port", instance.Port))
// Construct the URL for the chosen instance
url := fmt.Sprintf("http://%s:%d/codechef_user?username=ayushs_2k4", instance.Address, instance.Port)
slog.Info("Calling URL", slog.String("url", url))
// Make the HTTP GET request to the service
client := &http.Client{
Timeout: 5 * time.Second, // Set a timeout to avoid hanging requests
}
secondsToWait := 2
// Wait for some time without blocking the main thread
go func() {
slog.Info("Waiting before making the request", slog.Int("seconds", secondsToWait))
time.Sleep(time.Duration(secondsToWait) * time.Second)
slog.Info("Making HTTP request", slog.Int("seconds waited", secondsToWait))
// Perform the HTTP request in the Goroutine
resp, err := client.Get(url)
if err != nil {
slog.Error("Failed to make HTTP request", slog.String("error", err.Error()))
os.Exit(1)
}
defer resp.Body.Close()
// Read the response
body, err := io.ReadAll(resp.Body)
if err != nil {
slog.Error("Failed to read response", slog.String("error", err.Error()))
os.Exit(1)
}
// Log the response
slog.Info("Response from instance", slog.String("response", string(body)))
}()
// Log that the main thread is continuing execution
slog.Info("Main thread is not blocked, continuing execution...")
}