getConn returns a connection from the pool.
(ctx context.Context)
| 814 | |
| 815 | // getConn returns a connection from the pool. |
| 816 | func (p *ConnPool) getConn(ctx context.Context) (cn *Conn, err error) { |
| 817 | if p.closed() { |
| 818 | return nil, ErrClosed |
| 819 | } |
| 820 | |
| 821 | // Track pending requests in pool stats |
| 822 | atomic.AddUint32(&p.stats.PendingRequests, 1) |
| 823 | // Record pending request increment (UpDownCounter) |
| 824 | // Pass pool name explicitly since we don't have a connection yet |
| 825 | poolName := p.cfg.Name |
| 826 | if cb := getMetricPendingRequestsCallback(); cb != nil { |
| 827 | cb(ctx, 1, nil, poolName) |
| 828 | } |
| 829 | defer func() { |
| 830 | if err != nil { |
| 831 | // Failed to get connection, decrement pending requests |
| 832 | atomic.AddUint32(&p.stats.PendingRequests, ^uint32(0)) // -1 |
| 833 | // Record pending request decrement on failure |
| 834 | if cb := getMetricPendingRequestsCallback(); cb != nil { |
| 835 | cb(ctx, -1, nil, poolName) |
| 836 | } |
| 837 | } |
| 838 | }() |
| 839 | |
| 840 | // Track wait time - only call time.Now() if callback is registered |
| 841 | var waitStart time.Time |
| 842 | waitTimeCallback := getMetricConnectionWaitTimeCallback() |
| 843 | if waitTimeCallback != nil { |
| 844 | waitStart = time.Now() |
| 845 | } |
| 846 | if err = p.waitTurn(ctx); err != nil { |
| 847 | // Record timeout if applicable |
| 848 | if err == ErrPoolTimeout { |
| 849 | if cb := getMetricConnectionTimeoutCallback(); cb != nil { |
| 850 | cb(ctx, nil, "pool") |
| 851 | } |
| 852 | // Record general error metric for pool timeout |
| 853 | if cb := GetMetricErrorCallback(); cb != nil { |
| 854 | cb(ctx, "POOL_TIMEOUT", nil, "POOL_TIMEOUT", true, 0) |
| 855 | } |
| 856 | } |
| 857 | return nil, err |
| 858 | } |
| 859 | var waitDuration time.Duration |
| 860 | if waitTimeCallback != nil { |
| 861 | waitDuration = time.Since(waitStart) |
| 862 | } |
| 863 | |
| 864 | // Use cached time for health checks (max 50ms staleness is acceptable) |
| 865 | nowNs := getCachedTimeNs() |
| 866 | |
| 867 | // Lock-free atomic read - no mutex overhead! |
| 868 | hookManager := p.hookManager.Load() |
| 869 | |
| 870 | for attempts := 0; attempts < getAttempts; attempts++ { |
| 871 | |
| 872 | p.connsMu.Lock() |
| 873 | cn, err = p.popIdle() |
no test coverage detected