Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: force early refresh of instance info if connect fails #19

Merged
merged 2 commits into from
May 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ func (d *Dialer) Dial(ctx context.Context, instance string, opts ...DialOption)

conn, err := proxy.Dial(ctx, "tcp", addr)
if err != nil {
// refresh the instance info in case it caused the connection failure
i.ForceRefresh()
return nil, err
}
if c, ok := conn.(*net.TCPConn); ok {
Expand All @@ -152,6 +154,8 @@ func (d *Dialer) Dial(ctx context.Context, instance string, opts ...DialOption)
}
tlsConn := tls.Client(conn, tlsCfg)
if err := tlsConn.Handshake(); err != nil {
// refresh the instance info in case it caused the handshake failure
i.ForceRefresh()
tlsConn.Close()
return nil, fmt.Errorf("handshake failed: %w", err)
}
Expand Down
12 changes: 12 additions & 0 deletions internal/cloudsql/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,18 @@ func (i *Instance) ConnectInfo(ctx context.Context) (map[string]string, *tls.Con
return res.md.ipAddrs, res.tlsCfg, nil
}

// ForceRefresh triggers an immediate refresh operation to be scheduled and used for future connection attempts.
func (i *Instance) ForceRefresh() {
i.resultGuard.Lock()
defer i.resultGuard.Unlock()
// If the next refresh hasn't started yet, we can cancel it and start an immediate one
if i.next.Cancel() {
enocom marked this conversation as resolved.
Show resolved Hide resolved
i.next = i.scheduleRefresh(0)
}
// block all sequential connection attempts on the next refresh result
i.cur = i.next
}

// scheduleRefresh schedules a refresh operation to be triggered after a given duration. The returned refreshResult
// can be used to either Cancel or Wait for the operations result.
func (i *Instance) scheduleRefresh(d time.Duration) *refreshResult {
Expand Down
2 changes: 1 addition & 1 deletion internal/cloudsql/refresh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestFetchMetadata(t *testing.T) {
t.Fatalf("%s", err)
}
}
func TestFetchEmpheralCert(t *testing.T) {
func TestFetchEphemeralCert(t *testing.T) {
ctx := context.Background()

client, err := sqladmin.NewService(ctx)
Expand Down