File size: 2,368 Bytes
562a3ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
package main

import (
	"context"
	"encoding/json"
	"errors"
	"log/slog"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	// 1. Setup Logger
	// Use JSON handler for structured logging
	logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelDebug, // Log debug messages and above
	}))
	slog.SetDefault(logger) // Set as default logger for convenience

	logger.Info("Starting Stream Converter API Server...")

	// 2. Setup Router (Go 1.22+ ServeMux)
	mux := http.NewServeMux()

	// Wrap handler with logger middleware (or pass logger directly)
	chatHandler := func(w http.ResponseWriter, r *http.Request) {
		chatCompletionsHandler(logger, w, r)
	}
	mux.HandleFunc("POST /v1/chat/completions", chatHandler)

	// Add a simple health check endpoint
	mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
		logger.Debug("Health check accessed")
	})

	// 3. Configure HTTP Server
	server := &http.Server{
		Addr:         ":8080", // Listen on port 8080
		Handler:      mux,
		ReadTimeout:  10 * time.Second, // Example timeout values
		WriteTimeout: 90 * time.Second, // Longer for potential streaming
		IdleTimeout:  120 * time.Second,
	}

	// 4. Start Server in a Goroutine
	go func() {
		logger.Info("Server listening", "address", server.Addr)
		if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			logger.Error("Server failed to start", "error", err)
			os.Exit(1)
		}
	}()

	// 5. Graceful Shutdown Handling
	quit := make(chan os.Signal, 1)
	// signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	signal.Notify(quit, os.Interrupt, syscall.SIGTERM) // More portable signals

	// Block until a signal is received
	sig := <-quit
	logger.Info("Shutdown signal received", "signal", sig.String())

	// Create a context with timeout for shutdown
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// Attempt graceful shutdown
	if err := server.Shutdown(ctx); err != nil {
		logger.Error("Server shutdown failed", "error", err)
		os.Exit(1)
	}

	logger.Info("Server gracefully stopped")
}