Skip to content

Commit f69896b

Browse files
[MADE LOAD BALANCING VIA FIBER PREFORK]
1 parent 9f11251 commit f69896b

File tree

5 files changed

+145
-50
lines changed

5 files changed

+145
-50
lines changed

cmd/generate.go

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
package cmd
22

33
import (
4-
"embed" // For embedding templates
4+
"embed"
5+
56
"fmt"
6-
"net" // For checking port availability in generateCmd
7+
"net"
78
"os"
8-
"path/filepath" // For path manipulation
9-
"strconv" // For string to int conversion
9+
"path/filepath"
10+
"strconv"
11+
"os/exec"
1012

1113
"github.com/spf13/cobra"
1214
)
1315

14-
// CustomError is a simple wrapper for errors, useful for consistent error handling.
1516
type CustomError struct {
1617
Err error
1718
}
@@ -226,9 +227,93 @@ var listServicesCmd = &cobra.Command{
226227
},
227228
}
228229

230+
// modTidyAllCmd is the new Cobra command to run 'go mod tidy' in the pkg/ and all service directories.
231+
var modTidyAllCmd = &cobra.Command{
232+
Use: "mod-tidy-all",
233+
Short: "Runs 'go mod tidy' in pkg/ and all generated service directories",
234+
Long: "Executes 'go mod tidy' in the 'pkg/' folder and then in each subdirectory within the 'services/' folder, ensuring all module dependencies are clean.",
235+
RunE: func(cmd *cobra.Command, args []string) error {
236+
fmt.Println("Running 'go mod tidy' across the monorepo...")
237+
238+
originalDir, err := os.Getwd()
239+
if err != nil {
240+
return fmt.Errorf("failed to get current working directory: %w", err)
241+
}
242+
// Ensure we always return to the original directory at the end
243+
defer func() {
244+
if cerr := os.Chdir(originalDir); cerr != nil {
245+
fmt.Fprintf(os.Stderr, "Warning: Failed to change back to original directory '%s': %v\n", originalDir, cerr)
246+
}
247+
}()
248+
249+
// 1. Run 'go mod tidy' in the pkg/ directory
250+
pkgDir := filepath.Join(originalDir, "pkg") // Construct full path to pkg/
251+
if _, err := os.Stat(pkgDir); os.IsNotExist(err) {
252+
fmt.Printf("No 'pkg/' directory found, skipping 'go mod tidy' for pkg.\n")
253+
} else if err != nil {
254+
return fmt.Errorf("failed to check 'pkg/' directory: %w", err)
255+
} else {
256+
fmt.Printf("\nRunning 'go mod tidy' in: %s\n", pkgDir)
257+
if err := runGoModTidy(pkgDir); err != nil { // Run in pkgDir
258+
fmt.Fprintf(os.Stderr, "Error: Failed to run 'go mod tidy' in 'pkg/': %v\n", err)
259+
// Continue, but log the error
260+
}
261+
}
262+
263+
// 2. Iterate through 'services/' directory and run 'go mod tidy' in each service
264+
servicesDir := "services"
265+
serviceFolders, err := os.ReadDir(servicesDir)
266+
if err != nil {
267+
if os.IsNotExist(err) {
268+
fmt.Printf("No 'services/' directory found, skipping service-specific tidy.\n")
269+
// No error if services directory doesn't exist yet, just means nothing to tidy
270+
return nil
271+
}
272+
return fmt.Errorf("failed to read 'services/' directory: %w", err)
273+
}
274+
275+
for _, entry := range serviceFolders {
276+
if entry.IsDir() {
277+
servicePath := filepath.Join(servicesDir, entry.Name())
278+
fmt.Printf("\nRunning 'go mod tidy' in: %s\n", servicePath)
279+
280+
// Change to service directory
281+
if err := os.Chdir(servicePath); err != nil {
282+
fmt.Fprintf(os.Stderr, "Warning: Failed to change to service directory '%s': %v\n", servicePath, err)
283+
continue // Continue to next service
284+
}
285+
286+
// Run go mod tidy in the service directory
287+
if err := runGoModTidy("."); err != nil {
288+
fmt.Fprintf(os.Stderr, "Error: Failed to run 'go mod tidy' in '%s': %v\n", servicePath, err)
289+
// Optionally, you might want to stop here or collect all errors
290+
}
291+
292+
// Change back to original directory (handled by defer, but good practice for clarity in loop)
293+
if err := os.Chdir(originalDir); err != nil {
294+
return fmt.Errorf("failed to change back to original directory after processing '%s': %w", servicePath, err)
295+
}
296+
}
297+
}
298+
299+
fmt.Println("\n'go mod tidy' completed across all relevant directories. ✨")
300+
return nil
301+
},
302+
}
303+
304+
// runGoModTidy executes the 'go mod tidy' command in the specified directory.
305+
func runGoModTidy(dir string) error {
306+
cmd := exec.Command("go", "mod", "tidy")
307+
cmd.Dir = dir // Set the working directory for the command
308+
cmd.Stdout = os.Stdout
309+
cmd.Stderr = os.Stderr
310+
return cmd.Run()
311+
}
312+
229313
// init function to add commands to the root command.
230314
func init() {
231315
rootCmd.AddCommand(initCmd)
232316
rootCmd.AddCommand(generateCmd)
233317
rootCmd.AddCommand(listServicesCmd)
318+
rootCmd.AddCommand(modTidyAllCmd)
234319
}

cmd/templates/auth/main.tmpl

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"os"
66
"os/signal"
77
"syscall"
8-
"time" // For context timeout, if needed in shutdown
8+
"time"
99

1010
"github.com/gofiber/fiber/v2"
1111
"github.com/joho/godotenv"
@@ -17,61 +17,43 @@ import (
1717
)
1818

1919
func main() {
20-
// Load environment variables from .env file
21-
// This will typically contain JWT_SECRET and API_KEY for your middlewares
2220
if err := godotenv.Load(); err != nil {
2321
log.Println("No .env file found or failed to load. Using system environment variables.")
2422
}
2523

26-
// --- Service & Controller Wiring ---
27-
// Instantiate your authentication service
28-
// In a real application, you might pass a database connection here: internal.NewAuthService(db)
2924
authService := internal.NewAuthService()
30-
// Instantiate your authentication controller, injecting the service
3125
authController := internal.NewAuthController(authService)
3226

33-
// --- Fiber App Setup ---
34-
// Initialize a new Fiber application instance
35-
app := fiber.New()
27+
// --- Fiber App Setup with Prefork ---
28+
app := fiber.New(fiber.Config{
29+
Prefork: true, // Enable prefork for load balancing
30+
})
3631

37-
// Apply global Fiber middlewares defined in your shared pkg/http/middleware
38-
// This includes logging, CORS, recovery, security headers, etc.
3932
middleware.InitGlobalMiddlewares(app)
4033

41-
// Register all authentication-related routes with the Fiber application
42-
// This will set up your login and other auth endpoints.
4334
internal.RegisterAuthRoutes(app, authController)
4435

45-
// Set application port. This will be {{.Port}} as assigned by the CLI.
4636
port := os.Getenv("PORT")
4737
if port == "" {
48-
port = "{{.Port}}" // Default port for auth service, generated by CLI
38+
port = "{{.Port}}"
4939
}
5040

5141
// --- Start HTTP Server in a Goroutine ---
5242
go func() {
5343
log.Printf("Auth service is running on :%s", port)
5444
if err := app.Listen(":" + port); err != nil && err != fiber.ErrServerClosed {
55-
// Log fatal error if server fails to start or closes unexpectedly
5645
log.Fatalf("Fiber Listen error: %v", err)
5746
}
5847
}()
5948

6049
// --- Graceful Shutdown ---
61-
// Create a channel to listen for OS signals (e.g., Ctrl+C, SIGTERM from Docker/Kubernetes)
6250
quit := make(chan os.Signal, 1)
6351
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
6452

65-
// Block until a termination signal is received
6653
<-quit
6754
log.Println("Shutdown signal received, shutting down gracefully...")
6855

69-
// Attempt to gracefully shut down the Fiber app.
70-
// We use a context with a timeout to ensure shutdown doesn't hang indefinitely.
71-
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) // 5-second timeout
72-
defer cancel()
73-
74-
if err := app.ShutdownWithContext(ctx); err != nil {
56+
if err := app.Shutdown(); err != nil {
7557
log.Fatalf("Server forced to shutdown: %v", err)
7658
}
7759

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{{/*
2+
templates/config/consul_config.tmpl
3+
This template generates code for initializing and managing dynamic configuration
4+
via HashiCorp Consul's Key-Value store. It sets up initial config loading
5+
and a background goroutine to watch for changes.
6+
7+
Assumes:
8+
- appConfig struct is defined in pkg/config.
9+
- Required Consul client import: "github.com/hashicorp/consul/api"
10+
- Environment variable CONSUL_ADDR is set (e.g., "127.0.0.1:8500").
11+
- `fetchAndSetConsulConfigs` and `watchConsulConfig` functions exist in pkg/config.
12+
*/}}
13+
log.Println("Initializing dynamic configuration from Consul...")
14+
consulAddress := os.Getenv("CONSUL_ADDR")
15+
if consulAddress == "" {
16+
log.Fatal("CONSUL_ADDR environment variable is not set for Consul dynamic config.")
17+
}
18+
19+
consulConfig := api.DefaultConfig()
20+
consulConfig.Address = consulAddress
21+
consulClient, err := api.NewClient(consulConfig)
22+
if err != nil {
23+
log.Fatalf("Failed to create Consul client: %v", err)
24+
}
25+
26+
// Initial configuration load from Consul
27+
if err := config.FetchAndSetConsulConfigs(consulClient, "{{.Name | lower}}-service"); err != nil {
28+
log.Fatalf("Failed initial configuration load from Consul: %v", err)
29+
}
30+
log.Println("Initial configuration loaded from Consul.")
31+
32+
// Start a background goroutine to watch for configuration changes
33+
go config.WatchConsulConfig(consulClient, "{{.Name | lower}}-service")
34+
35+
// Use config.GetConfig() to access live configuration values throughout the application.

cmd/templates/config/etcd_config.tmpl

Whitespace-only changes.

cmd/templates/main.tmpl

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@ import (
44
"context"
55
"flag"
66
"log"
7-
"net/http"
87
"os"
98
"os/signal"
109
"syscall"
1110
"time"
1211

13-
"github.com/gorilla/mux"
12+
"github.com/gofiber/fiber/v2" // Import Fiber
1413
"github.com/joho/godotenv"
1514

16-
"pkg/http"
17-
"pkg/database/postgres"
15+
// You'll need to replace these with your actual package paths.
16+
"pkg/database/postgres"
1817
"src/internal"
1918
"pkg/entities"
2019
)
@@ -43,39 +42,33 @@ func main() {
4342
service := internal.NewUserService(db, entityModel)
4443
controller := internal.NewUserController(service)
4544

46-
// Setup router
47-
r := mux.NewRouter()
48-
internal.RegisterUserRoutes(r, controller)
45+
// --- Initialize Fiber and enable Prefork ---
46+
app := fiber.New(fiber.Config{
47+
Prefork: true, // This enables prefork for load balancing
48+
})
4949

50-
// Setup HTTP server with CORS middleware
51-
addr := ":" + *port
52-
srv := &http.Server{
53-
Addr: addr,
54-
Handler: http.WithCORS(r),
55-
}
50+
// Setup router (assumes a new RegisterUserRoutes that accepts *fiber.App)
51+
internal.RegisterUserRoutes(app, controller)
5652

5753
// Channel to listen for OS signals
5854
stop := make(chan os.Signal, 1)
5955
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
6056

6157
// Start server in goroutine
6258
go func() {
59+
addr := ":" + *port
6360
log.Printf("Service running on %s\n", addr)
64-
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
65-
log.Fatalf("Server error: %v", err)
61+
if err := app.Listen(addr); err != nil {
62+
log.Fatalf("Fiber Listen error: %v", err)
6663
}
6764
}()
6865

6966
// Wait for termination signal
7067
<-stop
7168
log.Println("Shutting down server...")
7269

73-
// Context for graceful shutdown
74-
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
75-
defer cancel()
76-
7770
// Shutdown server
78-
if err := srv.Shutdown(ctx); err != nil {
71+
if err := app.Shutdown(); err != nil {
7972
log.Fatalf("Server shutdown failed: %v", err)
8073
}
8174

0 commit comments

Comments
 (0)