feat: Introduce a Generic ResourceReconciler and a generic BaseWorkload to de-duplicate a lot of code

This commit is contained in:
TheiLLeniumStudios
2026-01-05 00:59:57 +01:00
parent c785067a44
commit 5548ce559a
31 changed files with 1491 additions and 1356 deletions
+69
View File
@@ -0,0 +1,69 @@
// Package http provides shared HTTP client functionality.
package http
import (
"net/http"
"net/url"
"time"
)
const (
// DefaultTimeout is the default HTTP client timeout.
DefaultTimeout = 30 * time.Second
// AlertingTimeout is the shorter timeout used for alerting.
AlertingTimeout = 10 * time.Second
)
// ClientConfig configures an HTTP client.
type ClientConfig struct {
// Timeout for HTTP requests.
Timeout time.Duration
// ProxyURL is an optional proxy URL.
ProxyURL string
// MaxIdleConns controls the maximum number of idle connections.
MaxIdleConns int
// MaxIdleConnsPerHost controls the maximum idle connections per host.
MaxIdleConnsPerHost int
// IdleConnTimeout is the maximum time an idle connection remains open.
IdleConnTimeout time.Duration
}
// DefaultConfig returns the default HTTP client configuration.
func DefaultConfig() ClientConfig {
return ClientConfig{
Timeout: DefaultTimeout,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
}
}
// NewClient creates a new HTTP client with the given configuration.
func NewClient(cfg ClientConfig) *http.Client {
transport := &http.Transport{
MaxIdleConns: cfg.MaxIdleConns,
MaxIdleConnsPerHost: cfg.MaxIdleConnsPerHost,
IdleConnTimeout: cfg.IdleConnTimeout,
}
if cfg.ProxyURL != "" {
if proxy, err := url.Parse(cfg.ProxyURL); err == nil {
transport.Proxy = http.ProxyURL(proxy)
}
}
return &http.Client{
Transport: transport,
Timeout: cfg.Timeout,
}
}
// NewDefaultClient creates an HTTP client with default configuration.
func NewDefaultClient() *http.Client {
return NewClient(DefaultConfig())
}
+142
View File
@@ -0,0 +1,142 @@
package http
import (
"net/http"
"testing"
"time"
)
func TestDefaultConfig(t *testing.T) {
cfg := DefaultConfig()
if cfg.Timeout != DefaultTimeout {
t.Errorf("expected timeout %v, got %v", DefaultTimeout, cfg.Timeout)
}
if cfg.MaxIdleConns != 100 {
t.Errorf("expected MaxIdleConns 100, got %d", cfg.MaxIdleConns)
}
if cfg.MaxIdleConnsPerHost != 10 {
t.Errorf("expected MaxIdleConnsPerHost 10, got %d", cfg.MaxIdleConnsPerHost)
}
if cfg.IdleConnTimeout != 90*time.Second {
t.Errorf("expected IdleConnTimeout 90s, got %v", cfg.IdleConnTimeout)
}
}
func TestNewClient(t *testing.T) {
tests := []struct {
name string
cfg ClientConfig
wantNil bool
}{
{
name: "default config",
cfg: DefaultConfig(),
wantNil: false,
},
{
name: "custom timeout",
cfg: ClientConfig{
Timeout: 5 * time.Second,
MaxIdleConns: 50,
MaxIdleConnsPerHost: 5,
IdleConnTimeout: 30 * time.Second,
},
wantNil: false,
},
{
name: "with proxy",
cfg: ClientConfig{
Timeout: DefaultTimeout,
ProxyURL: "http://proxy.example.com:8080",
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
wantNil: false,
},
{
name: "with invalid proxy URL",
cfg: ClientConfig{
Timeout: DefaultTimeout,
ProxyURL: "://invalid",
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
wantNil: false,
},
{
name: "zero values",
cfg: ClientConfig{
Timeout: 0,
},
wantNil: false,
},
}
for _, tt := range tests {
t.Run(
tt.name, func(t *testing.T) {
client := NewClient(tt.cfg)
if tt.wantNil && client != nil {
t.Error("expected nil client")
}
if !tt.wantNil && client == nil {
t.Error("expected non-nil client")
}
if client != nil {
if client.Timeout != tt.cfg.Timeout {
t.Errorf("expected timeout %v, got %v", tt.cfg.Timeout, client.Timeout)
}
transport, ok := client.Transport.(*http.Transport)
if !ok {
t.Fatal("expected *http.Transport")
}
if transport.MaxIdleConns != tt.cfg.MaxIdleConns {
t.Errorf("expected MaxIdleConns %d, got %d", tt.cfg.MaxIdleConns, transport.MaxIdleConns)
}
if transport.MaxIdleConnsPerHost != tt.cfg.MaxIdleConnsPerHost {
t.Errorf("expected MaxIdleConnsPerHost %d, got %d", tt.cfg.MaxIdleConnsPerHost, transport.MaxIdleConnsPerHost)
}
}
},
)
}
}
func TestNewDefaultClient(t *testing.T) {
client := NewDefaultClient()
if client == nil {
t.Fatal("expected non-nil client")
}
if client.Timeout != DefaultTimeout {
t.Errorf("expected timeout %v, got %v", DefaultTimeout, client.Timeout)
}
transport, ok := client.Transport.(*http.Transport)
if !ok {
t.Fatal("expected *http.Transport")
}
if transport.MaxIdleConns != 100 {
t.Errorf("expected MaxIdleConns 100, got %d", transport.MaxIdleConns)
}
if transport.MaxIdleConnsPerHost != 10 {
t.Errorf("expected MaxIdleConnsPerHost 10, got %d", transport.MaxIdleConnsPerHost)
}
}
func TestConstants(t *testing.T) {
if DefaultTimeout != 30*time.Second {
t.Errorf("expected DefaultTimeout 30s, got %v", DefaultTimeout)
}
if AlertingTimeout != 10*time.Second {
t.Errorf("expected AlertingTimeout 10s, got %v", AlertingTimeout)
}
}