Go version 1.8.3 In DB.QueryContext(), Go will close long live connection which exceeded the duration setted by DB.SetConnMaxLifetime(), the code is below database/sql/sql.go 895 func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error) { 896 db.mu.Lock() 897 if db.closed { 898 db.mu.Unlock() 899 return nil, errDBClosed 900 } 901 // Check if the context is expired. 902 select { 903 default: 904 case <-ctx.Done(): 905 db.mu.Unlock() 906 return nil, ctx.Err() 907 } 908 lifetime := db.maxLifetime 909 910 // Prefer a free connection, if possible. 911 numFree := len(db.freeConn) 912 if strategy == cachedOrNewConn && numFree > 0 { 913 conn := db.freeConn[0] 914 copy(db.freeConn, db.freeConn[1:]) 915 db.freeConn = db.freeConn[:numFree-1] 916 conn.inUse = true 917 db.mu.Unlock() * 918 if conn.expired(lifetime) {* * 919 conn.Close()* 920 return nil, driver.ErrBadConn 921 } 922 return conn, nil 923 }
The problem is if driver.Close() has some handshake to tear down the connection, this may introduce unexpected latency. But the driver.Conn interface not mention this. database/sql/driver/driver.go 143 type Conn interface { 144 // Prepare returns a prepared statement, bound to this connection. 145 Prepare(query string) (Stmt, error) 146 147 // Close invalidates and potentially stops any current 148 // prepared statements and transactions, marking this 149 // connection as no longer in use. 150 // 151 // Because the sql package maintains a free pool of 152 // connections and only calls Close when there's a surplus of 153 // idle connections, it shouldn't be necessary for drivers to 154 // do their own connection caching. 155 Close() error 156 157 // Begin starts and returns a new transaction. 158 // 159 // Deprecated: Drivers should implement ConnBeginTx instead (or additionally). 160 Begin() (Tx, error) 161 } There is already a goroutine to clean the connections, why still need a synchronous check? database/sql/sql.go 750 func (db *DB) connectionCleaner(d time.Duration) { 751 const minInterval = time.Second 752 753 if d < minInterval { 754 d = minInterval 755 } 756 t := time.NewTimer(d) 757 758 for { 759 select { 760 case <-t.C: 761 case <-db.cleanerCh: // maxLifetime was changed or db was closed. 762 } 763 764 db.mu.Lock() 765 d = db.maxLifetime 766 if db.closed || db.numOpen == 0 || d <= 0 { 767 db.cleanerCh = nil 768 db.mu.Unlock() 769 return 770 } 771 772 expiredSince := nowFunc().Add(-d) 773 var closing []*driverConn 774 for i := 0; i < len(db.freeConn); i++ { 775 c := db.freeConn[i] 776 if c.createdAt.Before(expiredSince) { 777 closing = append(closing, c) 778 last := len(db.freeConn) - 1 779 db.freeConn[i] = db.freeConn[last] 780 db.freeConn[last] = nil 781 db.freeConn = db.freeConn[:last] 782 i-- 783 } 784 } Is this by design or need to be fixed? -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.