@@ -224,6 +224,9 @@ type baseClient struct {
224224 // Maintenance notifications manager
225225 maintNotificationsManager * maintnotifications.Manager
226226 maintNotificationsManagerLock sync.RWMutex
227+
228+ credListeners map [uint64 ]auth.CredentialsListener
229+ credListenersLock sync.RWMutex
227230}
228231
229232func (c * baseClient ) clone () * baseClient {
@@ -237,6 +240,7 @@ func (c *baseClient) clone() *baseClient {
237240 onClose : c .onClose ,
238241 pushProcessor : c .pushProcessor ,
239242 maintNotificationsManager : maintNotificationsManager ,
243+ credListeners : c .credListeners ,
240244 }
241245 return clone
242246}
@@ -296,18 +300,43 @@ func (c *baseClient) _getConn(ctx context.Context) (*pool.Conn, error) {
296300 return cn , nil
297301}
298302
299- func (c * baseClient ) newReAuthCredentialsListener (poolCn * pool.Conn ) auth.CredentialsListener {
300- return auth .NewReAuthCredentialsListener (
301- c .reAuthConnection (poolCn ),
302- c .onAuthenticationErr (poolCn ),
303+ // connReAuthCredentialsListener returns a credentials listener that can be used to re-authenticate the connection.
304+ // The credentials listener is stored in a map, so that it can be reused for multiple connections.
305+ // The credentials listener is removed from the map when the connection is closed.
306+ func (c * baseClient ) connReAuthCredentialsListener (poolCn * pool.Conn ) (auth.CredentialsListener , func ()) {
307+ c .credListenersLock .RLock ()
308+ credListener , ok := c .credListeners [poolCn .GetID ()]
309+ c .credListenersLock .RUnlock ()
310+ if ok {
311+ return credListener .(auth.CredentialsListener ), func () {
312+ c .removeCredListener (poolCn )
313+ }
314+ }
315+ c .credListenersLock .Lock ()
316+ defer c .credListenersLock .Unlock ()
317+ newCredListener := auth .NewConnReAuthCredentialsListener (
318+ poolCn ,
319+ c .reAuthConnection (),
320+ c .onAuthenticationErr (),
303321 )
322+ c .credListeners [poolCn .GetID ()] = newCredListener
323+ return newCredListener , func () {
324+ c .removeCredListener (poolCn )
325+ }
326+ }
327+
328+ func (c * baseClient ) removeCredListener (poolCn * pool.Conn ) {
329+ c .credListenersLock .Lock ()
330+ defer c .credListenersLock .Unlock ()
331+ delete (c .credListeners , poolCn .GetID ())
304332}
305333
306- func (c * baseClient ) reAuthConnection (poolCn * pool.Conn ) func ( credentials auth.Credentials ) error {
307- return func (credentials auth.Credentials ) error {
334+ func (c * baseClient ) reAuthConnection () func ( poolCn * pool.Conn , credentials auth.Credentials ) error {
335+ return func (poolCn * pool. Conn , credentials auth.Credentials ) error {
308336 var err error
309337 username , password := credentials .BasicAuth ()
310338 ctx := context .Background ()
339+
311340 connPool := pool .NewSingleConnPool (c .connPool , poolCn )
312341 // hooksMixin are intentionally empty here
313342 cn := newConn (c .opt , connPool , nil )
@@ -320,8 +349,8 @@ func (c *baseClient) reAuthConnection(poolCn *pool.Conn) func(credentials auth.C
320349 return err
321350 }
322351}
323- func (c * baseClient ) onAuthenticationErr (poolCn * pool.Conn ) func ( err error ) {
324- return func (err error ) {
352+ func (c * baseClient ) onAuthenticationErr () func ( poolCn * pool.Conn , err error ) {
353+ return func (poolCn * pool. Conn , err error ) {
325354 if err != nil {
326355 if isBadConn (err , false , c .opt .Addr ) {
327356 // Close the connection to force a reconnection.
@@ -372,13 +401,20 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error {
372401
373402 username , password := "" , ""
374403 if c .opt .StreamingCredentialsProvider != nil {
404+ credListener , removeCredListener := c .connReAuthCredentialsListener (cn )
375405 credentials , unsubscribeFromCredentialsProvider , err := c .opt .StreamingCredentialsProvider .
376- Subscribe (c . newReAuthCredentialsListener ( cn ) )
406+ Subscribe (credListener )
377407 if err != nil {
378408 return fmt .Errorf ("failed to subscribe to streaming credentials: %w" , err )
379409 }
380- c .onClose = c .wrappedOnClose (unsubscribeFromCredentialsProvider )
381- cn .SetOnClose (unsubscribeFromCredentialsProvider )
410+
411+ unsubscribe := func () error {
412+ removeCredListener ()
413+ return unsubscribeFromCredentialsProvider ()
414+ }
415+ c .onClose = c .wrappedOnClose (unsubscribe )
416+ cn .SetOnClose (unsubscribe )
417+
382418 username , password = credentials .BasicAuth ()
383419 } else if c .opt .CredentialsProviderContext != nil {
384420 username , password , err = c .opt .CredentialsProviderContext (ctx )
@@ -496,6 +532,8 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error {
496532 }
497533 }
498534
535+ // mark the connection as usable and inited
536+ // once returned to the pool as idle, this connection can be used by other clients
499537 cn .SetUsable (true )
500538 cn .Inited .Store (true )
501539
0 commit comments