Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ DB_CONNECTION_STRING=postgres://user:password@localhost:5432/mydb?sslmode=disabl
DB_MAX_OPEN_CONNECTIONS=25
DB_MAX_IDLE_CONNECTIONS=5
DB_CONN_MAX_LIFETIME_MINUTES=5
DB_CONN_MAX_IDLE_TIME_MINUTES=5

# Server configuration
SERVER_HOST=0.0.0.0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Track expose_db_conn_max_idle_time_20260307 Context

- [Specification](./spec.md)
- [Implementation Plan](./plan.md)
- [Metadata](./metadata.json)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"track_id": "expose_db_conn_max_idle_time_20260307",
"type": "feature",
"status": "new",
"created_at": "2026-03-07T00:00:00Z",
"updated_at": "2026-03-07T00:00:00Z",
"description": "Expose DB ConnMaxIdleTime Configuration"
}
17 changes: 17 additions & 0 deletions conductor/archive/expose_db_conn_max_idle_time_20260307/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Implementation Plan: Expose DB ConnMaxIdleTime Configuration

## Phase 1: Configuration & Environment [checkpoint: fd1cdc3]
- [x] Task: Update `.env.example` with `DB_CONN_MAX_IDLE_TIME_MINUTES=5` (8385017)
- [x] Task: Update `internal/config/config.go` to include `DefaultDBConnMaxIdleTime` and `DBConnMaxIdleTime` field. (de33982)
- [x] Task: Write failing unit tests in `internal/config/config_test.go` for the new configuration field (Red Phase). (36b3f36)
- [x] Task: Implement `Load()` and `Validate()` in `internal/config/config.go` to support `DB_CONN_MAX_IDLE_TIME_MINUTES` (Green Phase). (c985d84)
- [x] Task: Conductor - User Manual Verification 'Phase 1: Configuration & Environment' (Protocol in workflow.md) (fd1cdc3)

## Phase 2: Dependency Injection & Integration [checkpoint: 67cebf7]
- [x] Task: Update `internal/app/di.go` to pass `DBConnMaxIdleTime` from the configuration to `database.Connect`. (396da05)
- [x] Task: Add integration or manual verification test to ensure `ConnMaxIdleTime` is correctly applied to the database pool. (0089ec3)
- [x] Task: Conductor - User Manual Verification 'Phase 2: Dependency Injection & Integration' (Protocol in workflow.md) (67cebf7)

## Phase 3: Documentation [checkpoint: 95eeb98]
- [x] Task: Update `docs/configuration.md` to document the `DB_CONN_MAX_IDLE_TIME_MINUTES` setting. (95ebccc)
- [x] Task: Conductor - User Manual Verification 'Phase 3: Documentation' (Protocol in workflow.md) (95eeb98)
28 changes: 28 additions & 0 deletions conductor/archive/expose_db_conn_max_idle_time_20260307/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Specification: Expose DB ConnMaxIdleTime Configuration

## Overview
Currently, the `Secrets` application allows configuring several database connection pool parameters (`DB_MAX_OPEN_CONNECTIONS`, `DB_MAX_IDLE_CONNECTIONS`, `DB_CONN_MAX_LIFETIME_MINUTES`), but it does not expose the `ConnMaxIdleTime` setting, which controls how long a connection can remain idle before being closed. This track will expose this configuration to provide better control over connection management.

## Functional Requirements
1. **Configuration Structure:** Add `DBConnMaxIdleTime` (of type `time.Duration`) to the `Config` struct in `internal/config/config.go`.
2. **Environment Variable:** Support loading this value from the environment variable `DB_CONN_MAX_IDLE_TIME_MINUTES`.
3. **Default Value:** Set a default value of 5 minutes (`DefaultDBConnMaxIdleTime = 5`).
4. **Dependency Injection:** Update `internal/app/di.go` to pass the `DBConnMaxIdleTime` from the configuration to the `database.Connect` function.
5. **Validation:** Ensure the value is validated (e.g., non-negative).
6. **Documentation:** Update `docs/configuration.md` to include information about the new `DB_CONN_MAX_IDLE_TIME_MINUTES` setting.
7. **Example Environment File:** Update `.env.example` to include the new environment variable with its default value.

## Non-Functional Requirements
- **Consistency:** Follow the existing naming conventions for database configuration.

## Acceptance Criteria
- The application correctly loads `DB_CONN_MAX_IDLE_TIME_MINUTES` from the environment.
- The default value of 5 minutes is used if the environment variable is not set.
- The `database.Connect` function receives and applies the configured `ConnMaxIdleTime`.
- Unit tests in `internal/config/config_test.go` verify the new configuration field.
- `docs/configuration.md` correctly reflects the new configuration option.
- `.env.example` includes the new variable.

## Out of Scope
- Modifying other database pool settings.
- Changing the default values for existing settings.
2 changes: 2 additions & 0 deletions conductor/tracks.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Project Tracks

This file tracks all major tracks for the project. Each track has its own detailed plan in its respective folder.

---
5 changes: 5 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ DB_CONNECTION_STRING=postgres://user:password@localhost:5432/mydb?sslmode=disabl
DB_MAX_OPEN_CONNECTIONS=25
DB_MAX_IDLE_CONNECTIONS=5
DB_CONN_MAX_LIFETIME_MINUTES=5
DB_CONN_MAX_IDLE_TIME_MINUTES=5

# Server configuration
SERVER_HOST=0.0.0.0
Expand Down Expand Up @@ -104,6 +105,10 @@ Maximum number of idle database connections (default: `5`).

Maximum lifetime of a connection in minutes (default: `5`).

### DB_CONN_MAX_IDLE_TIME_MINUTES

Maximum amount of time a connection may be idle in minutes (default: `5`).

## Server configuration

### SERVER_HOST
Expand Down
1 change: 1 addition & 0 deletions internal/app/di.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ func (c *Container) initDB(ctx context.Context) (*sql.DB, error) {
MaxOpenConnections: c.config.DBMaxOpenConnections,
MaxIdleConnections: c.config.DBMaxIdleConnections,
ConnMaxLifetime: c.config.DBConnMaxLifetime,
ConnMaxIdleTime: c.config.DBConnMaxIdleTime,
})
if err != nil {
return nil, fmt.Errorf("failed to connect to database: %w", err)
Expand Down
12 changes: 12 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (

DefaultDBMaxIdleConnections = 5
DefaultDBConnMaxLifetime = 5 // minutes
DefaultDBConnMaxIdleTime = 5 // minutes
DefaultLogLevel = "info"
DefaultAuthTokenExpiration = 14400 // seconds
DefaultRateLimitEnabled = true
Expand Down Expand Up @@ -70,6 +71,8 @@ type Config struct {
DBMaxIdleConnections int
// DBConnMaxLifetime is the maximum amount of time a connection may be reused.
DBConnMaxLifetime time.Duration
// DBConnMaxIdleTime is the maximum amount of time a connection may be idle.
DBConnMaxIdleTime time.Duration

// LogLevel is the logging level (e.g., "debug", "info", "warn", "error", "fatal", "panic").
LogLevel string
Expand Down Expand Up @@ -124,6 +127,10 @@ func (c *Config) Validate() error {
c,
validation.Field(&c.DBDriver, validation.Required, validation.In("postgres", "mysql")),
validation.Field(&c.DBConnectionString, validation.Required),
validation.Field(&c.DBMaxOpenConnections, validation.Min(0)),
validation.Field(&c.DBMaxIdleConnections, validation.Min(0)),
validation.Field(&c.DBConnMaxLifetime, validation.Min(0*time.Second)),
validation.Field(&c.DBConnMaxIdleTime, validation.Min(0*time.Second)),
validation.Field(&c.ServerPort, validation.Required, validation.Min(1), validation.Max(65535)),
validation.Field(
&c.ServerReadTimeout,
Expand Down Expand Up @@ -220,6 +227,11 @@ func Load() (*Config, error) {
DefaultDBConnMaxLifetime,
time.Minute,
),
DBConnMaxIdleTime: env.GetDuration(
"DB_CONN_MAX_IDLE_TIME_MINUTES",
DefaultDBConnMaxIdleTime,
time.Minute,
),

// Logging
LogLevel: env.GetString("LOG_LEVEL", DefaultLogLevel),
Expand Down
13 changes: 8 additions & 5 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ func TestLoad(t *testing.T) {
assert.Equal(t, 25, cfg.DBMaxOpenConnections)
assert.Equal(t, 5, cfg.DBMaxIdleConnections)
assert.Equal(t, 5*time.Minute, cfg.DBConnMaxLifetime)
assert.Equal(t, 5*time.Minute, cfg.DBConnMaxIdleTime)
assert.Equal(t, "info", cfg.LogLevel)
assert.Equal(t, 14400*time.Second, cfg.AuthTokenExpiration)
assert.Equal(t, true, cfg.RateLimitEnabled)
Expand Down Expand Up @@ -473,18 +474,20 @@ func TestLoad(t *testing.T) {
{
name: "load custom database configuration",
envVars: map[string]string{
"DB_DRIVER": "mysql",
"DB_CONNECTION_STRING": "user:password@tcp(localhost:3306)/testdb",
"DB_MAX_OPEN_CONNECTIONS": "50",
"DB_MAX_IDLE_CONNECTIONS": "10",
"DB_CONN_MAX_LIFETIME_MINUTES": "10",
"DB_DRIVER": "mysql",
"DB_CONNECTION_STRING": "user:password@tcp(localhost:3306)/testdb",
"DB_MAX_OPEN_CONNECTIONS": "50",
"DB_MAX_IDLE_CONNECTIONS": "10",
"DB_CONN_MAX_LIFETIME_MINUTES": "10",
"DB_CONN_MAX_IDLE_TIME_MINUTES": "10",
},
validate: func(t *testing.T, cfg *Config) {
assert.Equal(t, "mysql", cfg.DBDriver)
assert.Equal(t, "user:password@tcp(localhost:3306)/testdb", cfg.DBConnectionString)
assert.Equal(t, 50, cfg.DBMaxOpenConnections)
assert.Equal(t, 10, cfg.DBMaxIdleConnections)
assert.Equal(t, 10*time.Minute, cfg.DBConnMaxLifetime)
assert.Equal(t, 10*time.Minute, cfg.DBConnMaxIdleTime)
},
},
{
Expand Down
Loading