From b5dd72e78313b7586734bb6de6bb9918e5b42fa0 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Tue, 14 Jan 2020 11:45:09 -0800 Subject: [PATCH] Add in configuration options for connection pool Closes #4 --- README.md | 20 +++++++++++++------- db.go | 14 ++++++++++++++ layer_proc.go | 1 + layer_table.go | 13 +++++++------ main.go | 3 +++ 5 files changed, 38 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 7bc27d03..02c3ddfb 100644 --- a/README.md +++ b/README.md @@ -55,12 +55,19 @@ If you want to alter default values other than the database connection, use the ```toml # Database connection DbConnection = "user=you host=localhost dbname=yourdb" -# Accept connections on this default (default all) +# Close pooled connections after this interval +DbPoolMaxConnLifeTime = "1h" +# Hold no more than this number of connections in the database pool +DbPoolMaxConns = 4 +# Look to read html templates from this directory +AssetsPath = "./assets" +# Accept connections on this subnet (default accepts on all) HttpHost = "0.0.0.0" # Accept connections on this port HttpPort = 7800 # Advertise URLs relative to this server name -UrlBase = "http://yourserver.com/" +# default is to looke this up from incoming request headers +# UrlBase = "http://yourserver.com/" # Resolution to quantize vector tiles to DefaultResolution = 4096 # Padding to add to vector tiles @@ -199,7 +206,7 @@ Most developers will just use the `tileurl` as is, but it possible to add some p * `limit` controls the number of features to write to a tile, the default is 50000. * `resolution` controls the resolution of a tile, the default is 4096 units per side for a tile. * `buffer` controls the size of the extra data buffer for a tile, the default is 256 units. -* `attributes` is a comma-separated list of attributes to include in the tile. For wide tables with large numbers of columns, this allows a slimmer tile to be composd. +* `attributes` is a comma-separated list of attributes to include in the tile. For wide tables with large numbers of columns, this allows a slimmer tile to be composed. For example: @@ -277,12 +284,11 @@ AS $$ FROM ne_50m_admin_0_countries t, bounds WHERE ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326)) AND upper(t.name) LIKE (upper(name_prefix) || '%') - LIMIT 10000 ) - SELECT ST_AsMVT(mvtgeom.*, 'public.countries_name') FROM mvtgeom + SELECT ST_AsMVT(mvtgeom, 'public.countries_name') FROM mvtgeom; $$ LANGUAGE 'sql' -STABLE +VOLATILE PARALLEL SAFE; COMMENT ON FUNCTION public.countries_name IS 'Filters the countries table by the initial letters of the name using the "name_prefix" parameter.'; @@ -355,7 +361,7 @@ AS $$ AND ST_DWithin(p.geom, args.click, radius) LIMIT 10000 ) - SELECT ST_AsMVT(mvtgeom.*, 'public.parcels_in_radius') FROM mvtgeom + SELECT ST_AsMVT(mvtgeom, 'public.parcels_in_radius') FROM mvtgeom $$ LANGUAGE 'sql' STABLE diff --git a/db.go b/db.go index e8eacfb3..6e7089a1 100644 --- a/db.go +++ b/db.go @@ -6,6 +6,7 @@ import ( "regexp" "strconv" "strings" + "time" // Database "github.com/jackc/pgx/v4" @@ -29,6 +30,19 @@ func DbConnect() (*pgxpool.Pool, error) { log.Fatal(err) } + // Read and parse connection lifetime + dbPoolMaxLifeTime, errt := time.ParseDuration(viper.GetString("DbPoolMaxConnLifeTime")) + if errt != nil { + log.Fatal(errt) + } + config.MaxConnLifetime = dbPoolMaxLifeTime + + // Read and parse max connections + dbPoolMaxConns := viper.GetInt32("DbPoolMaxConns") + if dbPoolMaxConns > 0 { + config.MaxConns = dbPoolMaxConns + } + // Read current log level and use one less-fine level // below that config.ConnConfig.Logger = logrusadapter.NewLogger(log.New()) diff --git a/layer_proc.go b/layer_proc.go index 0b6edcbc..969e5bfc 100644 --- a/layer_proc.go +++ b/layer_proc.go @@ -183,6 +183,7 @@ func GetFunctionLayers() ([]LayerFunction, error) { AND p.proargnames[1:3] = ARRAY['z'::text, 'x'::text, 'y'::text] AND prorettype = 17 AND has_function_privilege(Format('%s.%s(%s)', n.nspname, p.proname, oidvectortypes(proargtypes)), 'execute') + ORDER BY 1 ` db, connerr := DbConnect() diff --git a/layer_table.go b/layer_table.go index 516076cb..1521f1ba 100644 --- a/layer_table.go +++ b/layer_table.go @@ -407,6 +407,7 @@ func GetTableLayers() ([]LayerTable, error) { layerSql := ` SELECT + Format('%s.%s', n.nspname, c.relname) AS id, n.nspname AS schema, c.relname AS table, coalesce(d.description, '') AS description, @@ -437,6 +438,7 @@ func GetTableLayers() ([]LayerTable, error) { AND has_table_privilege(c.oid, 'select') AND has_schema_privilege(n.oid, 'usage') AND postgis_typmod_srid(a.atttypmod) > 0 + ORDER BY 1 ` db, connerr := DbConnect() @@ -454,13 +456,13 @@ func GetTableLayers() ([]LayerTable, error) { for rows.Next() { var ( - schema, table, description, geometry_column string - srid int - geometry_type, id_column string - atts pgtype.TextArray + id, schema, table, description, geometry_column string + srid int + geometry_type, id_column string + atts pgtype.TextArray ) - err := rows.Scan(&schema, &table, &description, &geometry_column, + err := rows.Scan(&id, &schema, &table, &description, &geometry_column, &srid, &geometry_type, &id_column, &atts) if err != nil { return nil, err @@ -492,7 +494,6 @@ func GetTableLayers() ([]LayerTable, error) { } // "schema.tablename" is our unique key for table layers - id := fmt.Sprintf("%s.%s", schema, table) lyr := LayerTable{ Id: id, Schema: schema, diff --git a/main.go b/main.go index 236e0c72..e3440f76 100644 --- a/main.go +++ b/main.go @@ -57,6 +57,9 @@ func main() { viper.SetDefault("DefaultMaxZoom", 22) viper.SetDefault("Debug", false) viper.SetDefault("AssetsPath", "./assets") + // 1d, 1h, 1m, 1s, see https://golang.org/pkg/time/#ParseDuration + viper.SetDefault("DbPoolMaxConnLifeTime", "1h") + viper.SetDefault("DbPoolMaxConns", 4) // Read environment configuration first if dbUrl := os.Getenv("DATABASE_URL"); dbUrl != "" {