diff --git a/pkg/dbmanager/config.go b/pkg/dbmanager/config.go index 7213eb6..e690827 100644 --- a/pkg/dbmanager/config.go +++ b/pkg/dbmanager/config.go @@ -221,7 +221,10 @@ func (cc *ConnectionConfig) ApplyDefaults(global *ManagerConfig) { cc.ConnectTimeout = 10 * time.Second } if cc.QueryTimeout == 0 { - cc.QueryTimeout = 30 * time.Second + cc.QueryTimeout = 2 * time.Minute // Default to 2 minutes + } else if cc.QueryTimeout < 2*time.Minute { + // Enforce minimum of 2 minutes + cc.QueryTimeout = 2 * time.Minute } // Default ORM @@ -325,14 +328,29 @@ func (cc *ConnectionConfig) buildPostgresDSN() string { dsn += fmt.Sprintf(" search_path=%s", cc.Schema) } + // Add statement_timeout for query execution timeout (in milliseconds) + if cc.QueryTimeout > 0 { + timeoutMs := int(cc.QueryTimeout.Milliseconds()) + dsn += fmt.Sprintf(" statement_timeout=%d", timeoutMs) + } + return dsn } func (cc *ConnectionConfig) buildSQLiteDSN() string { - if cc.FilePath != "" { - return cc.FilePath + filepath := cc.FilePath + if filepath == "" { + filepath = ":memory:" } - return ":memory:" + + // Add query parameters for timeouts + // Note: SQLite driver supports _timeout parameter (in milliseconds) + if cc.QueryTimeout > 0 { + timeoutMs := int(cc.QueryTimeout.Milliseconds()) + filepath += fmt.Sprintf("?_timeout=%d", timeoutMs) + } + + return filepath } func (cc *ConnectionConfig) buildMSSQLDSN() string { @@ -344,6 +362,24 @@ func (cc *ConnectionConfig) buildMSSQLDSN() string { dsn += fmt.Sprintf("&schema=%s", cc.Schema) } + // Add connection timeout (in seconds) + if cc.ConnectTimeout > 0 { + timeoutSec := int(cc.ConnectTimeout.Seconds()) + dsn += fmt.Sprintf("&connection timeout=%d", timeoutSec) + } + + // Add dial timeout for TCP connection (in seconds) + if cc.ConnectTimeout > 0 { + dialTimeoutSec := int(cc.ConnectTimeout.Seconds()) + dsn += fmt.Sprintf("&dial timeout=%d", dialTimeoutSec) + } + + // Add read timeout (in seconds) - enforces timeout for reading data + if cc.QueryTimeout > 0 { + readTimeoutSec := int(cc.QueryTimeout.Seconds()) + dsn += fmt.Sprintf("&read timeout=%d", readTimeoutSec) + } + return dsn } diff --git a/pkg/dbmanager/providers/sqlite.go b/pkg/dbmanager/providers/sqlite.go index 3ce5c99..6f70970 100644 --- a/pkg/dbmanager/providers/sqlite.go +++ b/pkg/dbmanager/providers/sqlite.go @@ -76,8 +76,12 @@ func (p *SQLiteProvider) Connect(ctx context.Context, cfg ConnectionConfig) erro // Don't fail connection if WAL mode cannot be enabled } - // Set busy timeout to handle locked database - _, err = db.ExecContext(ctx, "PRAGMA busy_timeout=5000") + // Set busy timeout to handle locked database (minimum 2 minutes = 120000ms) + busyTimeout := cfg.GetQueryTimeout().Milliseconds() + if busyTimeout < 120000 { + busyTimeout = 120000 // Enforce minimum of 2 minutes + } + _, err = db.ExecContext(ctx, fmt.Sprintf("PRAGMA busy_timeout=%d", busyTimeout)) if err != nil { if cfg.GetEnableLogging() { logger.Warn("Failed to set busy timeout for SQLite", "error", err) diff --git a/pkg/server/manager.go b/pkg/server/manager.go index f1b7877..61f16dc 100644 --- a/pkg/server/manager.go +++ b/pkg/server/manager.go @@ -411,7 +411,9 @@ func newInstance(cfg Config) (*serverInstance, error) { return nil, fmt.Errorf("handler cannot be nil") } - // Set default timeouts + // Set default timeouts with minimum of 10 minutes for connection timeouts + minConnectionTimeout := 10 * time.Minute + if cfg.ShutdownTimeout == 0 { cfg.ShutdownTimeout = 30 * time.Second } @@ -419,13 +421,22 @@ func newInstance(cfg Config) (*serverInstance, error) { cfg.DrainTimeout = 25 * time.Second } if cfg.ReadTimeout == 0 { - cfg.ReadTimeout = 15 * time.Second + cfg.ReadTimeout = minConnectionTimeout + } else if cfg.ReadTimeout < minConnectionTimeout { + // Enforce minimum of 10 minutes + cfg.ReadTimeout = minConnectionTimeout } if cfg.WriteTimeout == 0 { - cfg.WriteTimeout = 15 * time.Second + cfg.WriteTimeout = minConnectionTimeout + } else if cfg.WriteTimeout < minConnectionTimeout { + // Enforce minimum of 10 minutes + cfg.WriteTimeout = minConnectionTimeout } if cfg.IdleTimeout == 0 { - cfg.IdleTimeout = 60 * time.Second + cfg.IdleTimeout = minConnectionTimeout + } else if cfg.IdleTimeout < minConnectionTimeout { + // Enforce minimum of 10 minutes + cfg.IdleTimeout = minConnectionTimeout } addr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)