Component(s)
receiver/sqlserver
Is your feature request related to a problem? Please describe.
Proposal: Implement Shared Database Connection Pool in SQL Server Receiver
Problem Statement
The SQL Server receiver currently creates a separate database connection pool for each scraper (one per enabled query). This design has significant performance and resource efficiency implications:
Current Architecture
- Each metric query (Database IO, Performance Counters, Properties, Wait Stats) creates its own scraper
- Each scraper creates its own
*sql.DB connection pool via dbProviderFunc()
- All pools connect to the same SQL Server instance with the same credentials
Issues with Current Design
-
Connection Pool Fragmentation
- Multiple independent pools instead of one optimized pool
- Each pool manages its own queue, idle timeout, and lifecycle independently
- Query execution is not load-balanced across a shared resource
-
Resource Inefficiency
- If 4 scrapers are enabled, resources are allocated 4x for connection management
- Each pool maintains minimum connections separately
- Higher memory overhead from redundant pool metadata
-
Configuration and Tuning Complexity
- Connection pool settings (max connections, idle timeout, max lifetime) multiply across pools
- Difficult to understand actual resource consumption from configuration alone
- Hard to tune for specific deployment scenarios
-
Connection Limit Exhaustion
- Database connection limits are reached sooner than necessary
- In environments with strict connection quotas, fewer concurrent scrapers can run
- No ability to gracefully degrade across pools
-
Observability Gaps
- No clear insight into how many actual connections are open to the database
- Pool-level metrics are scattered across multiple independent pools
- Harder to diagnose connection-related issues
Evidence
- TODO comment in
factory.go (lines 123-124): "Test if this needs to be re-defined for each scraper"
- Suggests original developers recognized this as a potential issue
Date: 2026-03-28
Credits: AI-Assisted (Claude Code)
Describe the solution you'd like
Proposed Solution
Implement a shared connection pool at the receiver level that all scrapers use:
Architecture Changes
-
Create pool at receiver initialization (in createMetricsReceiver/createLogsReceiver)
- Single
*sql.DB connection pool created once per receiver instance
- Owned and managed by the receiver
-
Pass pool to scrapers instead of a provider function
- Modify
newSQLServerScraper() to accept a pre-initialized *sql.DB
- Remove
dbProviderFunc parameter
-
Update scraper lifecycle
Start(): Verify connection works, but don't create pool
Shutdown(): Close scraper resources, but not the pool (receiver owns it)
- Receiver's
Shutdown(): Close the single shared pool
Code Changes Overview
Before:
// factory.go
dbProviderFunc := func() (*sql.DB, error) {
return sql.Open("sqlserver", getDBConnectionString(cfg))
}
// Each scraper creates its own pool
func (s *sqlServerScraperHelper) Start(...) error {
s.db, err = s.dbProviderFunc() // Creates new pool
...
}
After:
// factory.go - create pool once
db, err := sql.Open("sqlserver", getDBConnectionString(cfg))
if err != nil {
return nil, fmt.Errorf("failed to open database connection: %w", err)
}
// Pass same pool to all scrapers
for _, query := range queries {
scraper := newSQLServerScraper(..., db) // Use shared pool
}
Benefits
| Aspect |
Current |
Proposed |
Improvement |
| Connection Pools |
N (one per scraper) |
1 |
Connections gets reused across scrapers especailly now that more and more scrapers are getting added |
| Resource Usage |
O(N) |
O(1) |
Linear → Constant |
| Pool Tuning |
Complex, scattered |
Centralized |
Simpler configuration |
| Database Connection Limits |
Hit sooner |
Hit later |
Better resource efficiency |
| Observability |
Fragmented |
Unified |
Single source of truth |
| Scalability |
Poor (fixed overhead) |
Good (overhead doesn't grow) |
Better for many scrapers |
Implementation Details
Files to Modify
-
📄 factory.go:123-124 - TODO about re-defining pool per scraper
- Create connection pool in
createMetricsReceiver() and createLogsReceiver()
- Pass pool to
setupSQLServerScrapers() and setupSQLServerLogsScrapers()
- Update these functions to pass
*sql.DB to scrapers instead of dbProviderFunc
-
📄 scraper.go:101-110 - Current Start() creates pool
- Remove
dbProviderFunc field from sqlServerScraperHelper
- Update
newSQLServerScraper() signature to accept *sql.DB
- Simplify
Start() to verify connection without creating pool
- Simplify
Shutdown() to not close the pool (receiver owns it)
Testing Strategy
- Unit Tests: Verify single pool is reused across scrapers
- Integration Tests: Ensure all scrapers work with shared pool
- Resource Tests: Confirm reduced connection overhead
- Error Tests: Handle pool initialization failures gracefully
Backwards Compatibility
User-facing: No breaking changes
- Configuration schema unchanged
- Metrics output unchanged
- Behavior from user perspective unchanged
Implementation: Minor changes to internal scraper lifecycle
dbProviderFunc becomes implementation detail
- Error handling improved
Risks and Mitigation
| Risk |
Severity |
Mitigation |
| Pool exhaustion if misconfigured |
Medium |
Add documentation on connection limits; default to safe values |
| Harder to test scrapers in isolation |
Low |
Keep scraper tests using mock pools; integration tests use real pool |
| Pool close timing |
Low |
Clear ownership model: receiver owns, scrapers don't close |
Performance Impact
Expected Improvements
- Memory: Reduced overhead from N→1 pool managers
- Latency: Minimal (may slightly improve if pool has better utilization)
- Throughput: Potentially better (shared pool can batch work better)
- Connection count: Reduced by ~75% with 4 scrapers (4 separate pools → 1 shared)
Success Criteria
- ✅ All scrapers function with single shared pool
- ✅ Resource usage reduced (measurable in integration tests)
- ✅ All existing tests pass
- ✅ New integration test validates shared pool behavior
- ✅ Documentation updated with resource consumption information
Next Steps
- Community Discussion: Present this proposal for feedback
- Design Review: Get sign-off from SQL Server receiver maintainers
- Implementation: Create PR with changes
- Testing: Comprehensive testing across scenarios
- Release: Include in next minor version with release notes
Date: 2026-03-28
Credits: AI-Assisted (Claude Code)
Describe alternatives you've considered
No response
Additional context
No response
Tip
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.
Component(s)
receiver/sqlserver
Is your feature request related to a problem? Please describe.
Proposal: Implement Shared Database Connection Pool in SQL Server Receiver
Problem Statement
The SQL Server receiver currently creates a separate database connection pool for each scraper (one per enabled query). This design has significant performance and resource efficiency implications:
Current Architecture
*sql.DBconnection pool viadbProviderFunc()Issues with Current Design
Connection Pool Fragmentation
Resource Inefficiency
Configuration and Tuning Complexity
Connection Limit Exhaustion
Observability Gaps
Evidence
factory.go(lines 123-124): "Test if this needs to be re-defined for each scraper"Date: 2026-03-28
Credits: AI-Assisted (Claude Code)
Describe the solution you'd like
Proposed Solution
Implement a shared connection pool at the receiver level that all scrapers use:
Architecture Changes
Create pool at receiver initialization (in
createMetricsReceiver/createLogsReceiver)*sql.DBconnection pool created once per receiver instancePass pool to scrapers instead of a provider function
newSQLServerScraper()to accept a pre-initialized*sql.DBdbProviderFuncparameterUpdate scraper lifecycle
Start(): Verify connection works, but don't create poolShutdown(): Close scraper resources, but not the pool (receiver owns it)Shutdown(): Close the single shared poolCode Changes Overview
Before:
After:
Benefits
Implementation Details
Files to Modify
📄 factory.go:123-124 - TODO about re-defining pool per scraper
createMetricsReceiver()andcreateLogsReceiver()setupSQLServerScrapers()andsetupSQLServerLogsScrapers()*sql.DBto scrapers instead ofdbProviderFunc📄 scraper.go:101-110 - Current Start() creates pool
dbProviderFuncfield fromsqlServerScraperHelpernewSQLServerScraper()signature to accept*sql.DBStart()to verify connection without creating poolShutdown()to not close the pool (receiver owns it)Testing Strategy
Backwards Compatibility
User-facing: No breaking changes
Implementation: Minor changes to internal scraper lifecycle
dbProviderFuncbecomes implementation detailRisks and Mitigation
Performance Impact
Expected Improvements
Success Criteria
Next Steps
Date: 2026-03-28
Credits: AI-Assisted (Claude Code)
Describe alternatives you've considered
No response
Additional context
No response
Tip
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding
+1orme too, to help us triage it. Learn more here.