Skip to content

feat(database): async connect with background retry and health middleware - #158

Open
Gautam7352 wants to merge 6 commits into
devfrom
pr/async-db-health
Open

feat(database): async connect with background retry and health middleware#158
Gautam7352 wants to merge 6 commits into
devfrom
pr/async-db-health

Conversation

@Gautam7352

@Gautam7352 Gautam7352 commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

What's changed

This PR overhauls how the backend connects to and monitors the database, replacing a blocking/polling approach with a non-blocking, self-healing connection model.

Database connection

  • Connect() is now non-blocking — the HTTP server starts immediately without waiting for the DB to be ready
  • sql.Open is called once outside the retry loop (it only validates the DSN, not the connection)
  • Retries ping every 5s until the DB is reachable, then stores the pool via atomic.Pointer[sql.DB]
  • Replaced the raw DB *sql.DB global with GetDB() accessor to eliminate data races on connect/reconnect

Health monitoring

  • Added StartHealthMonitor() — a two-speed background ping loop:
    • Healthy: pings every 30s (observability only)
    • Degraded: switches to 5s pings immediately when a failure is detected, to recover as fast as possible
  • MarkDegraded() can be signaled from anywhere without blocking (buffered channel, drops duplicates)
  • HandleQueryError() in services/middleware calls MarkDegraded() on real DB errors (excludes sql.ErrNoRows)
  • /health endpoint reads the cached atomic flag instead of doing a live ping on every call
  • Pool stats are only logged on recovery from degraded state, not on every tick

Other

  • Removed .env file loading and godotenv dependency — configuration is read exclusively from environment variables
  • Added structured JSON logger (logger package) replacing raw log.Printf calls
  • Removed watchConnection polling loop — sql.DB manages pool health internally

…ware

- Replace blocking Connect() with non-blocking background goroutine
- Retry DB connection every 5s indefinitely; server starts without waiting
- Add watchConnection() to detect and recover from lost connections
- Expose IsHealthy() via atomic int32 flag (no mutex contention)
- Add DBHealthCheck() middleware returning 503 when DB is unreachable
- Add testing.go helper SetHealthForTest() for unit tests (non-production only)
- Update main.go to use new Connect(cfg) signature and register middleware
@Gautam7352 Gautam7352 changed the title feat(database): async connect with background retry and health middle… feat(database): async connect with background retry and health middleware Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant