【问题标题】:Golang Pgx pool dynamic configurationGolang Pgx 池动态配置
【发布时间】:2021-03-12 11:50:27
【问题描述】:

我有一个带有 postgres 的 RDS 实例,我通过 IAM 用户进行身份验证。密码是每 15 分钟刷新一次的令牌:


    authToken, err := rdsutils.BuildAuthToken(Endpoint, "mars-east-4", "iamuser", envCredentials)
    if err != nil {
        return "", err
    }

但是我已经看到连接池在令牌过期后引发身份验证错误的问题,并且我没有找到任何好的方法。

我的想法是创建一个函数GetPool并将其注入我的存储库,该函数将返回一个池对象pgxpool.Pool

func (p Pool) GetPool() (*pgxpool.Pool, error) {
    config, err := p.getConfig()
    if err != nil {
        return nil, err
    }

    pool, err := pgxpool.ConnectConfig(context.Background(), config)
    if err != nil {
        return nil, err
    }

    return pool, nil
}

getConfig 内部将调用BuildAuthToken,但仅每 15 分钟一次(伪代码):

if time > 15minutes {
  return BuildAuthToken()
}

因此,如果 15 分钟过去了,我将重新验证令牌,否则我将使用我已经拥有的令牌。 这将是最终的解决方案

func (p Pool) GetPool() (*pgxpool.Pool, error) {
    // Pseudocode
    if p.time < 15minutes {
      return p.Pool, nil
    }

    config, err := p.getConfig()
    if err != nil {
        return nil, err
    }

    pool, err := pgxpool.ConnectConfig(context.Background(), config)
    if err != nil {
        return nil, err
    }

    p.Pool = pool
    p.time = time.Now()
    return pool, nil
}

那么这种方法效率低吗?有更好的方法吗?另外,由于我将在服务器中使用它,竞争条件如何? 谢谢

【问题讨论】:

    标签: go amazon-rds


    【解决方案1】:

    最近pgx为pgxpool.Pool引入了BeforeConnect钩子

    这是我目前的解决方案

    func (p *Pool) getConfig() (*pgxpool.Config, error) {
        config, err := pgxpool.ParseConfig("")
        if err != nil {
            return nil, err
        }
    
        /**
        This will refresh the password if the connection is expired
        */
        config.BeforeConnect = func(ctx context.Context, config *pgx.ConnConfig) error {
            if p.isTokenExpired() {
                creds, err := p.getCredentials()
                if err != nil {
                    return err
                }
    
                config.User = creds.user
                config.Password = creds.password
                config.Host = creds.host
                config.Database = creds.database
                config.Port = creds.port
                p.cachedCredentials = creds
                p.expire = time.Now()
            } else {
                config.User = p.cachedCredentials.user
                config.Password = p.cachedCredentials.password
                config.Host = p.cachedCredentials.host
                config.Database = p.cachedCredentials.database
                config.Port = p.cachedCredentials.port
            }
    
            return nil
        }
    
        return config, nil
    }
    
    

    如果轮询需要创建一个新连接,它将首先调用 BeforeConnect 钩子,getCredentials 将从 AWS IAM 检索令牌,但这只会在令牌接近其到期时间时发生(根据AWS)

    PS:此功能尚未发布,但已合并到master。要使用它,您必须获得最新的提交

    【讨论】:

      猜你喜欢
      • 2021-08-31
      • 2021-11-23
      • 2010-11-18
      • 1970-01-01
      • 1970-01-01
      • 2022-01-27
      • 1970-01-01
      • 1970-01-01
      • 2018-01-05
      相关资源
      最近更新 更多