summaryrefslogtreecommitdiffstats
path: root/internal/config
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-14 09:44:55 -0800
committerbndw <ben@bdw.to>2026-02-14 09:44:55 -0800
commitfe3708eaf495613cc6e2340b821795f25811d6ed (patch)
tree061f4b1c2938919ab38e0bc840c34d7c35bad42f /internal/config
parent688548d4ac3293449a88913275f886fd2e103cdf (diff)
fix: optimize SQLite connection pooling for single-writer architecture
Remove misleading max_connections config option and properly configure SQLite connection pooling in the storage layer. Changes: - Set MaxOpenConns(1) for optimal SQLite performance - Set MaxIdleConns(1) to keep connection alive - Set ConnMaxLifetime(0) to never close connection - Remove max_connections and max_lifetime from DatabaseConfig - Update docs to clarify SQLite's single-writer architecture Rationale: SQLite is an embedded database with a single-writer lock. Multiple connections cause lock contention and reduce performance. WAL mode allows concurrent reads from the same connection, making connection pooling unnecessary and counterproductive. This change makes the configuration clearer and ensures optimal SQLite performance by using a single long-lived connection.
Diffstat (limited to 'internal/config')
-rw-r--r--internal/config/README.md9
-rw-r--r--internal/config/config.go16
-rw-r--r--internal/config/config_test.go5
3 files changed, 8 insertions, 22 deletions
diff --git a/internal/config/README.md b/internal/config/README.md
index 87d6fa1..79e1b89 100644
--- a/internal/config/README.md
+++ b/internal/config/README.md
@@ -75,11 +75,8 @@ database:
75 # Path to SQLite database file 75 # Path to SQLite database file
76 path: "relay.db" 76 path: "relay.db"
77 77
78 # Maximum number of open connections 78 # Note: Connection pooling is automatically configured for SQLite.
79 max_connections: 10 79 # SQLite uses a single connection for optimal performance.
80
81 # Connection max lifetime
82 max_lifetime: "1h"
83 80
84# Authentication configuration 81# Authentication configuration
85auth: 82auth:
@@ -264,8 +261,6 @@ Server:
264 261
265Database: 262Database:
266 Path: "relay.db" 263 Path: "relay.db"
267 MaxConnections: 10
268 MaxLifetime: 1h
269 264
270Auth: 265Auth:
271 Enabled: false 266 Enabled: false
diff --git a/internal/config/config.go b/internal/config/config.go
index 87ca4eb..91e79f7 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -31,9 +31,9 @@ type ServerConfig struct {
31 31
32// DatabaseConfig holds database configuration. 32// DatabaseConfig holds database configuration.
33type DatabaseConfig struct { 33type DatabaseConfig struct {
34 Path string `yaml:"path"` 34 Path string `yaml:"path"`
35 MaxConnections int `yaml:"max_connections"` 35 // Note: SQLite connection pooling is handled internally in the storage layer.
36 MaxLifetime time.Duration `yaml:"max_lifetime"` 36 // SQLite works best with a single connection due to its single-writer architecture.
37} 37}
38 38
39// AuthConfig holds authentication configuration. 39// AuthConfig holds authentication configuration.
@@ -106,9 +106,7 @@ func Default() *Config {
106 WriteTimeout: 30 * time.Second, 106 WriteTimeout: 30 * time.Second,
107 }, 107 },
108 Database: DatabaseConfig{ 108 Database: DatabaseConfig{
109 Path: "relay.db", 109 Path: "relay.db",
110 MaxConnections: 10,
111 MaxLifetime: 1 * time.Hour,
112 }, 110 },
113 Auth: AuthConfig{ 111 Auth: AuthConfig{
114 Enabled: false, 112 Enabled: false,
@@ -239,12 +237,6 @@ func applyEnvOverrides(cfg *Config) {
239 if val := os.Getenv("MUXSTR_DATABASE_PATH"); val != "" { 237 if val := os.Getenv("MUXSTR_DATABASE_PATH"); val != "" {
240 cfg.Database.Path = val 238 cfg.Database.Path = val
241 } 239 }
242 if val := os.Getenv("MUXSTR_DATABASE_MAX_CONNECTIONS"); val != "" {
243 var n int
244 if _, err := fmt.Sscanf(val, "%d", &n); err == nil {
245 cfg.Database.MaxConnections = n
246 }
247 }
248 240
249 // Auth 241 // Auth
250 if val := os.Getenv("MUXSTR_AUTH_ENABLED"); val != "" { 242 if val := os.Getenv("MUXSTR_AUTH_ENABLED"); val != "" {
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index 50d9b67..e1df1aa 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -257,7 +257,6 @@ server:
257 257
258database: 258database:
259 path: "test.db" 259 path: "test.db"
260 max_lifetime: "30m"
261 260
262rate_limit: 261rate_limit:
263 cleanup_interval: "10m" 262 cleanup_interval: "10m"
@@ -282,7 +281,7 @@ rate_limit:
282 t.Errorf("expected write timeout 2m, got %v", cfg.Server.WriteTimeout) 281 t.Errorf("expected write timeout 2m, got %v", cfg.Server.WriteTimeout)
283 } 282 }
284 283
285 if cfg.Database.MaxLifetime != 30*time.Minute { 284 if cfg.RateLimit.CleanupInterval != 10*time.Minute {
286 t.Errorf("expected max lifetime 30m, got %v", cfg.Database.MaxLifetime) 285 t.Errorf("expected cleanup interval 10m, got %v", cfg.RateLimit.CleanupInterval)
287 } 286 }
288} 287}