@@ -3,9 +3,11 @@ package postgresql
33import (
44 "context"
55 "fmt"
6+ "os"
7+ "time"
8+
69 "github.com/aws/aws-sdk-go-v2/credentials"
710 "github.com/aws/aws-sdk-go-v2/service/sts"
8- "os"
911
1012 "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
1113 "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
@@ -21,8 +23,12 @@ import (
2123)
2224
2325const (
24- defaultProviderMaxOpenConnections = 20
25- defaultExpectedPostgreSQLVersion = "9.0.0"
26+ defaultProviderMaxOpenConnections = 20 // sql.DB Default
27+ defaultProviderMaxIdleConnections = 0
28+ // Keep connection lifetimes short by default, to prevent blocking 'destroy' actions on database instance resources.
29+ defaultProviderConnectionMaxIdleTime = time .Second * 5
30+ defaultProviderConnectionMaxLifetime = time .Second * 10
31+ defaultExpectedPostgreSQLVersion = "9.0.0"
2632)
2733
2834// Provider returns a terraform.ResourceProvider.
@@ -192,6 +198,35 @@ func Provider() *schema.Provider {
192198 Description : "Maximum number of connections to establish to the database. Zero means unlimited." ,
193199 ValidateFunc : validation .IntAtLeast (- 1 ),
194200 },
201+ "max_idle_connections" : {
202+ Type : schema .TypeInt ,
203+ Optional : true ,
204+ Default : defaultProviderMaxIdleConnections ,
205+ Description : "Maximum number of idle connections to hold for the database. " +
206+ "NOTE: Idle connections that aren't cleaned-up can cause problems if a database is destroyed in " +
207+ "the same plan. The default is 0 to prevent that issue." ,
208+ ValidateFunc : validation .IntAtLeast (- 1 ),
209+ },
210+ "connection_max_idle_time" : {
211+ Type : schema .TypeString ,
212+ Optional : true ,
213+ Default : defaultProviderConnectionMaxIdleTime .String (),
214+ Description : "Duration to hold idle connections to the database. Setting to 0 will hold connections " + "" +
215+ "forever. " +
216+ "NOTE: Idle connections that aren't cleaned-up can cause problems if a database is destroyed in " +
217+ "the same plan. This should be > 0 to prevent that." ,
218+ ValidateFunc : validateParsableDuration ,
219+ },
220+ "connection_max_lifetime" : {
221+ Type : schema .TypeString ,
222+ Optional : true ,
223+ Default : defaultProviderConnectionMaxLifetime .String (),
224+ Description : "Maximum lifetime of any connections to the database. Setting to 0 will hold " +
225+ "connections forever. " +
226+ "NOTE: Idle connections that aren't cleaned-up can cause problems if a database is destroyed in " +
227+ "the same plan. This should be > 0 to prevent that." ,
228+ ValidateFunc : validateParsableDuration ,
229+ },
195230 "expected_version" : {
196231 Type : schema .TypeString ,
197232 Optional : true ,
@@ -236,6 +271,13 @@ func validateExpectedVersion(v interface{}, key string) (warnings []string, erro
236271 return
237272}
238273
274+ func validateParsableDuration (v any , _ string ) (warnings []string , errors []error ) {
275+ if _ , err := time .ParseDuration (v .(string )); err != nil {
276+ errors = append (errors , fmt .Errorf ("invalid duration (%q): %w" , v .(string ), err ))
277+ }
278+ return
279+ }
280+
239281func getRDSAuthToken (region string , profile string , role string , username string , host string , port int ) (string , error ) {
240282 endpoint := fmt .Sprintf ("%s:%d" , host , port )
241283
@@ -367,6 +409,10 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
367409 password = d .Get ("password" ).(string )
368410 }
369411
412+ // Safe to ignore the error, since this is already checked in validation
413+ connMaxIdleTime , _ := time .ParseDuration (d .Get ("connection_max_idle_time" ).(string ))
414+ connMaxLifetime , _ := time .ParseDuration (d .Get ("connection_max_lifetime" ).(string ))
415+
370416 config := Config {
371417 Scheme : d .Get ("scheme" ).(string ),
372418 Host : host ,
@@ -379,6 +425,9 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
379425 ApplicationName : "Terraform provider" ,
380426 ConnectTimeoutSec : d .Get ("connect_timeout" ).(int ),
381427 MaxConns : d .Get ("max_connections" ).(int ),
428+ MaxIdleConns : d .Get ("max_idle_connections" ).(int ),
429+ ConnMaxIdleTime : connMaxIdleTime ,
430+ ConnMaxLifetime : connMaxLifetime ,
382431 ExpectedVersion : version ,
383432 SSLRootCertPath : d .Get ("sslrootcert" ).(string ),
384433 GCPIAMImpersonateServiceAccount : d .Get ("gcp_iam_impersonate_service_account" ).(string ),
0 commit comments