Skip to content

fix: Connection retry logic#576

Open
atorrescogollo wants to merge 8 commits into
cyrilgdn:mainfrom
atorrescogollo:pr-retry-connections
Open

fix: Connection retry logic#576
atorrescogollo wants to merge 8 commits into
cyrilgdn:mainfrom
atorrescogollo:pr-retry-connections

Conversation

@atorrescogollo

Copy link
Copy Markdown

Fixes #495

This PR adds support for automatically retrying PostgreSQL connections in terraform-provider-postgresql, similar to the behavior already implemented in terraform-provider-mysql

Currently, unstable network issues can cause PostgreSQL connections to fail on the first attempt, leading to unnecessary errors. By adding retry logic, the provider becomes more resilient and reliable, especially in environments where the connection is unstable (for example, when accessing through a SOCKS proxy).

@atorrescogollo

Copy link
Copy Markdown
Author

@cyrilgdn could you review this please? I'm right now forced to run a fork

@simonfrey-pf

Copy link
Copy Markdown

@cyrilgdn I checked the code, it looks good. Could you maybe give it a second look and merge it. Would be a highly appreciated featured. Thank you!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves connection resilience in terraform-provider-postgresql by adding configurable retry behavior when establishing PostgreSQL connections, targeting intermittent failures (e.g., through proxies) as described in issue #495.

Changes:

  • Adds provider configuration knobs for connection retries and retry timeout.
  • Implements retry + ping validation during Client.Connect() to reduce transient connection failures.
  • Introduces a configurable DB connection max lifetime and applies it to opened connections.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
postgresql/provider.go Adds new provider schema fields and wires them into the runtime Config.
postgresql/config.go Adds retry-based connection establishment and applies connection max lifetime settings.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread postgresql/provider.go Outdated
Comment thread postgresql/config.go Outdated
Comment thread postgresql/config.go Outdated
Comment thread postgresql/config.go Outdated
@simonfrey-pf

Copy link
Copy Markdown

@atorrescogollo The feedback from copilot seems valid, could you work over the PR based on it?

- Default conn_max_lifetime_seconds to 0 (unlimited) to preserve
  pre-retry-logic behavior for existing users.
- Narrow dbRegistryLock scope so dialing/retrying no longer stalls
  Connect() calls for other DSNs; handle the publish race.
- Close the leaked *sql.DB handle on each failed retry attempt.
- Classify non-retryable errors (bad auth, unknown database) so
  retries fail fast instead of exhausting max_conn_retries.
- Document zero-value behavior for max_conn_retries.
- Add unit tests for connectWithRetry's attempt-counting behavior.
@atorrescogollo

Copy link
Copy Markdown
Author

@simonfrey-pf can you review again?

Comment thread postgresql/provider.go Outdated
Comment thread postgresql/provider.go Outdated
Comment thread postgresql/config.go
max_conn_retries now counts actual retries as documented ('zero means no
retries'): retryCount is incremented only when a retry is performed, so
MaxConnRetries=N yields 1 initial attempt plus N retries. Previously it
counted total attempts, one short of the documented behavior.

conn_max_lifetime_seconds validation tightened from IntAtLeast(-1) to
IntAtLeast(0), since SetConnMaxLifetime treats all non-positive values as
unlimited and -1 carried no distinct meaning.
@atorrescogollo

Copy link
Copy Markdown
Author

@simonfrey-pf I think I addressed all your review comments. Can you review once again?

@simonfrey-pf simonfrey-pf left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from this one typo looks good to me

@cyrilgdn Could you check this PR and then LGTM :D Looking forward to have this feature, as in our stack it really is needed 😄

Comment thread website/docs/index.html.markdown Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comment thread postgresql/config.go
Comment on lines +355 to 366
connectRetryTimeout := time.Duration(c.config.ConnectionRetryTimeoutSeconds) * time.Second
retryError := retry.RetryContext(ctx, connectRetryTimeout, func() *retry.RetryError {
if c.config.Scheme == "postgres" {
db, err = sql.Open(proxyDriverName, dsn)
db, err = sql.Open(postgresDriverName, dsn)
} else if c.config.Scheme == "gcppostgres" && c.config.GCPIAMImpersonateServiceAccount != "" {
db, err = openImpersonatedGCPDBConnection(context.Background(), dsn, c.config.GCPIAMImpersonateServiceAccount)
db, err = openImpersonatedGCPDBConnection(ctx, dsn, c.config.GCPIAMImpersonateServiceAccount)
} else {
db, err = postgres.Open(context.Background(), dsn)
db, err = postgres.Open(ctx, dsn)
}

if err == nil {
err = db.Ping()
err = db.PingContext(ctx)
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cyrilgdn I think copilot is wrong here. Each attempt is already bounded by connect_timeout. RetryContext uses connection_retry_timeout_seconds as the total budget across retries

Comment thread postgresql/config.go
Comment thread postgresql/provider.go
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@simonfrey-pf

Copy link
Copy Markdown

@cyrilgdn Could we get this one over the finish linie? @atorrescogollo and me invested already quite some time to get the PR into shape. If there is anything else you would like us to change, please let us know 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unstable connection to postgres via proxy

4 participants