140 lines
3.7 KiB
Go
140 lines
3.7 KiB
Go
// Package main provides the GPT-Load 2.0 process entry point.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"gpt-load/internal/app"
|
|
"gpt-load/internal/container"
|
|
"gpt-load/internal/platform/config"
|
|
"gpt-load/internal/platform/redact"
|
|
"gpt-load/internal/platform/utils"
|
|
)
|
|
|
|
func main() {
|
|
if len(os.Args) > 1 {
|
|
os.Exit(dispatchCommand(os.Args[1:], os.Stdout, os.Stderr))
|
|
}
|
|
if err := runServer(); err != nil {
|
|
logrus.WithError(err).Error("GPT-Load stopped with an error")
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func dispatchCommand(args []string, stdout, stderr io.Writer) int {
|
|
if len(args) == 0 {
|
|
printHelp(stdout)
|
|
return 0
|
|
}
|
|
|
|
switch args[0] {
|
|
case "help", "-h", "--help":
|
|
printHelp(stdout)
|
|
return 0
|
|
case "migrate-keys":
|
|
fmt.Fprintln(stderr, "migrate-keys will be available in a later release")
|
|
return 1
|
|
default:
|
|
fmt.Fprintf(stderr, "Unknown command: %s\n", args[0])
|
|
fmt.Fprintln(stderr, "Run 'gpt-load help' for usage.")
|
|
return 1
|
|
}
|
|
}
|
|
|
|
func printHelp(output io.Writer) {
|
|
fmt.Fprintln(output, "GPT-Load - self-hosted AI API key gateway")
|
|
fmt.Fprintln(output)
|
|
fmt.Fprintln(output, "Usage:")
|
|
fmt.Fprintln(output, " gpt-load Start the gateway")
|
|
fmt.Fprintln(output, " gpt-load help Display this help message")
|
|
fmt.Fprintln(output)
|
|
fmt.Fprintln(output, "Deferred Commands:")
|
|
fmt.Fprintln(output, " migrate-keys Key rotation support will be available in a later release")
|
|
}
|
|
|
|
func runServer() error {
|
|
dependencyContainer, err := container.BuildContainer()
|
|
if err != nil {
|
|
return fmt.Errorf("build dependency container: %w", err)
|
|
}
|
|
|
|
if err := dependencyContainer.Invoke(func(cfg *config.Config, runtimeRedactor *redact.Redactor) {
|
|
utils.SetupLogger(utils.LogConfig{
|
|
Level: cfg.Log.Level,
|
|
Format: cfg.Log.Format,
|
|
})
|
|
logrus.AddHook(redact.NewHook(runtimeRedactor))
|
|
}); err != nil {
|
|
return fmt.Errorf("configure logger: %w", err)
|
|
}
|
|
|
|
var application *app.App
|
|
var cfg *config.Config
|
|
if err := dependencyContainer.Invoke(func(resolvedApp *app.App, resolvedConfig *config.Config) {
|
|
application = resolvedApp
|
|
cfg = resolvedConfig
|
|
}); err != nil {
|
|
return fmt.Errorf("resolve application: %w", err)
|
|
}
|
|
quit := make(chan os.Signal, 2)
|
|
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
|
|
defer signal.Stop(quit)
|
|
|
|
if err := application.Start(); err != nil {
|
|
cleanupCtx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
defer cancel()
|
|
_ = application.Stop(cleanupCtx)
|
|
return fmt.Errorf("start application: %w", err)
|
|
}
|
|
|
|
var serveErr error
|
|
var firstSignal os.Signal
|
|
select {
|
|
case firstSignal = <-quit:
|
|
logrus.WithFields(logrus.Fields{
|
|
"event": "shutdown.requested",
|
|
"signal": firstSignal.String(),
|
|
}).Info("shutdown requested by signal")
|
|
case serveErr = <-application.ServeErrors():
|
|
}
|
|
|
|
shutdownCtx, cancel := context.WithTimeout(
|
|
context.Background(),
|
|
time.Duration(cfg.Server.GracefulShutdownTimeout)*time.Second,
|
|
)
|
|
defer cancel()
|
|
stopResult := make(chan error, 1)
|
|
go func() { stopResult <- application.Stop(shutdownCtx) }()
|
|
forceReason := "signal_during_shutdown"
|
|
if firstSignal != nil {
|
|
forceReason = "second_signal"
|
|
}
|
|
select {
|
|
case secondSignal := <-quit:
|
|
logrus.WithFields(logrus.Fields{
|
|
"event": "shutdown.force",
|
|
"signal": secondSignal.String(),
|
|
"reason": forceReason,
|
|
}).Warn("additional shutdown signal received; forcing shutdown")
|
|
cancel()
|
|
if err := <-stopResult; err != nil {
|
|
return errors.Join(serveErr, fmt.Errorf("stop application: %w", err))
|
|
}
|
|
return serveErr
|
|
case err := <-stopResult:
|
|
if err != nil {
|
|
return errors.Join(serveErr, fmt.Errorf("stop application: %w", err))
|
|
}
|
|
return serveErr
|
|
}
|
|
}
|