Add server port and timeout configuration (#360)

This commit is contained in:
shenlan 2025-10-01 21:38:01 +08:00 committed by GitHub
parent 97168a00a7
commit b434eb0afc
4 changed files with 71 additions and 1 deletions

View File

@ -2,7 +2,9 @@ package main
import (
"context"
"errors"
"log/slog"
"net/http"
"os"
"strings"
@ -84,7 +86,22 @@ var rootCmd = &cobra.Command{
api.RegisterRoutes(conn, cfg.Sync.Repo.Proxy),
)
r.Run() // listen and serve on 0.0.0.0:8080
addr := cfg.Server.Addr
if addr == "" {
addr = ":8080"
}
srv := &http.Server{
Addr: addr,
Handler: r,
ReadTimeout: cfg.Server.ReadTimeout.Duration,
WriteTimeout: cfg.Server.WriteTimeout.Duration,
}
logger.Info("starting http server", "addr", addr)
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
logger.Error("http server shutdown", "err", err)
}
},
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"time"
"gopkg.in/yaml.v3"
)
@ -121,6 +122,42 @@ type API struct {
} `yaml:"askai"`
}
// Duration is a thin wrapper around time.Duration to support YAML unmarshalling
// from strings like "15s".
type Duration struct {
time.Duration
}
// UnmarshalYAML implements yaml unmarshalling for Duration values.
func (d *Duration) UnmarshalYAML(value *yaml.Node) error {
var raw string
if err := value.Decode(&raw); err != nil {
return err
}
if raw == "" {
d.Duration = 0
return nil
}
parsed, err := time.ParseDuration(raw)
if err != nil {
return err
}
d.Duration = parsed
return nil
}
// String returns the duration formatted using time.Duration's String method.
func (d Duration) String() string {
return d.Duration.String()
}
// ServerCfg contains HTTP server runtime configuration.
type ServerCfg struct {
Addr string `yaml:"addr"`
ReadTimeout Duration `yaml:"readTimeout"`
WriteTimeout Duration `yaml:"writeTimeout"`
}
type Config struct {
Log Log `yaml:"log"`
Global Global `yaml:"global"`
@ -132,6 +169,7 @@ type Config struct {
Embedding EmbeddingCfg `yaml:"embedding"`
Chunking ChunkingCfg `yaml:"chunking"`
API API `yaml:"api"`
Server ServerCfg `yaml:"server"`
}
// Load reads the configuration file at the provided path. When path is empty,

View File

@ -3,6 +3,7 @@ package config
import (
"os"
"testing"
"time"
)
// TestLoad ensures the configuration file is loaded correctly.
@ -27,4 +28,13 @@ func TestLoad(t *testing.T) {
if cfg.API.AskAI.Timeout != 100 {
t.Fatalf("unexpected askai timeout %d", cfg.API.AskAI.Timeout)
}
if cfg.Server.Addr != ":8090" {
t.Fatalf("unexpected server addr %q", cfg.Server.Addr)
}
if cfg.Server.ReadTimeout.Duration != 15*time.Second {
t.Fatalf("unexpected server read timeout %s", cfg.Server.ReadTimeout)
}
if cfg.Server.WriteTimeout.Duration != 15*time.Second {
t.Fatalf("unexpected server write timeout %s", cfg.Server.WriteTimeout)
}
}

View File

@ -1,3 +1,8 @@
server:
addr: ":8090"
readTimeout: 15s
writeTimeout: 15s
global:
redis:
addr: "127.0.0.1:6379"