Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
174 lines
3.5 KiB
Go
174 lines
3.5 KiB
Go
package rdbms
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type (
|
|
ConnConfig struct {
|
|
DriverName string
|
|
DataSourceName string
|
|
DBName string
|
|
|
|
// MaskedDSN is a DSN with sensitive data masked
|
|
// each connection is handling that independently
|
|
MaskedDSN string
|
|
|
|
// MaxOpenConns sets maximum number of open connections to the database
|
|
// defaults to same value as set in the db/sql
|
|
MaxOpenConns int
|
|
|
|
// ConnMaxLifetime sets the maximum amount of time a connection may be reused
|
|
// defaults to same value as set in the db/sql
|
|
ConnMaxLifetime time.Duration
|
|
|
|
// MaxIdleConns sets the maximum number of connections in the idle connection pool
|
|
// defaults to same value as set in the db/sql
|
|
MaxIdleConns int
|
|
|
|
// ConnTryPatience sets time window in which we do not complaining about failed connection tries
|
|
ConnTryPatience time.Duration
|
|
|
|
// ConnTryBackoffDelay sets backoff delay after failed try
|
|
ConnTryBackoffDelay time.Duration
|
|
|
|
// ConnTryTimeout sets timeout per try
|
|
ConnTryTimeout time.Duration
|
|
|
|
// ConnTryMax maximum number of retries for getting the connection
|
|
ConnTryMax int
|
|
}
|
|
)
|
|
|
|
var (
|
|
dsnMasker = regexp.MustCompile(`(.)(?:.*)(.):(.)(?:.*)(.)@`)
|
|
)
|
|
|
|
func (c *ConnConfig) SetDefaults() {
|
|
if c.MaskedDSN == "" {
|
|
c.MaskedDSN = c.DBName + "://********:********@********:********/********"
|
|
}
|
|
|
|
if c.MaxIdleConns == 0 {
|
|
// Same as default in the db/sql
|
|
c.MaxIdleConns = 32
|
|
}
|
|
|
|
if c.MaxOpenConns == 0 {
|
|
// Same as default in the db/sql
|
|
c.MaxOpenConns = 256
|
|
}
|
|
|
|
if c.ConnMaxLifetime == 0 {
|
|
// Same as default in the db/sql
|
|
c.ConnMaxLifetime = 10 * time.Minute
|
|
}
|
|
|
|
// ** ** ** ** ** ** ** ** ** ** ** ** ** **
|
|
|
|
if c.ConnTryPatience == 0 {
|
|
//c.ConnTryPatience = 1 * time.Minute
|
|
}
|
|
|
|
if c.ConnTryBackoffDelay == 0 {
|
|
c.ConnTryBackoffDelay = 10 * time.Second
|
|
}
|
|
|
|
if c.ConnTryTimeout == 0 {
|
|
c.ConnTryTimeout = 30 * time.Second
|
|
}
|
|
|
|
if c.ConnTryMax == 0 {
|
|
c.ConnTryMax = 99
|
|
}
|
|
}
|
|
|
|
// ParseExtra parses extra params (params starting with *)
|
|
// from DSN's querystring (after ?)
|
|
func (c *ConnConfig) ParseExtra() (err error) {
|
|
// Make sure we only got qs
|
|
const q = "?"
|
|
var (
|
|
dsn = c.DataSourceName
|
|
qs string
|
|
)
|
|
|
|
if pos := strings.LastIndex(dsn, q); pos == -1 {
|
|
return nil
|
|
} else {
|
|
// Trim qs from DSN, we'll re-attach the remaining params
|
|
c.DataSourceName, qs = dsn[:pos], dsn[pos+1:]
|
|
}
|
|
|
|
var vv url.Values
|
|
if vv, err = url.ParseQuery(qs); err != nil {
|
|
return err
|
|
}
|
|
|
|
var (
|
|
val string
|
|
|
|
parseInt = func(s string) (int, error) {
|
|
if tmp, err := strconv.ParseInt(s, 10, 32); err != nil {
|
|
return 0, err
|
|
} else {
|
|
return int(tmp), nil
|
|
}
|
|
|
|
}
|
|
)
|
|
|
|
const storePrefixChar = "*"
|
|
|
|
for key := range vv {
|
|
val = vv.Get(key)
|
|
|
|
if storePrefixChar != key[:1] {
|
|
// skip non-store specific config
|
|
continue
|
|
}
|
|
|
|
switch key {
|
|
case "*connTryPatience":
|
|
c.ConnTryPatience, err = time.ParseDuration(val)
|
|
|
|
case "*connTryBackoffDelay":
|
|
c.ConnTryBackoffDelay, err = time.ParseDuration(val)
|
|
|
|
case "*connTryTimeout":
|
|
c.ConnTryTimeout, err = time.ParseDuration(val)
|
|
|
|
case "*connMaxTries":
|
|
c.ConnTryMax, err = parseInt(val)
|
|
|
|
case "*connMaxOpen":
|
|
c.MaxOpenConns, err = parseInt(val)
|
|
|
|
case "*connMaxLifetime":
|
|
c.ConnMaxLifetime, err = time.ParseDuration(val)
|
|
|
|
case "*connMaxIdle":
|
|
c.MaxIdleConns, err = parseInt(val)
|
|
|
|
default:
|
|
err = fmt.Errorf("unknown key %q", key)
|
|
}
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("invalid store configuration for key %q: %w", key, err)
|
|
}
|
|
|
|
delete(vv, key)
|
|
}
|
|
|
|
// Encode QS back to DSN
|
|
c.DataSourceName += q + vv.Encode()
|
|
|
|
return nil
|
|
}
|