From 8b10a067a2711d90db6778625440560320778321 Mon Sep 17 00:00:00 2001 From: Eno Compton Date: Mon, 15 Apr 2024 14:48:10 -0600 Subject: [PATCH] feat: add support for a lazy refresh When clients run the Proxy in environments where the CPU may be throttled, the background connection info refresh operation can fail to complete, causing connection errors. This commit introduces an option for a lazy refresh. Connection info is retrieved on an as needed-basis and cached based on the associated certificate's expiration. No background goroutine runs, unlike the default refresh ahead cache. Enable it like so: ./cloud-sql-proxy --lazy-refresh A lazy refresh may result in increased latency (more requests will be subject to waiting for the refresh to complete), but gains in reliability. Fixes #2183 --- cmd/options.go | 8 ++++++++ cmd/options_test.go | 12 ++++++++++++ cmd/root.go | 5 ++++- cmd/root_test.go | 7 +++++++ go.mod | 4 +--- go.sum | 2 ++ internal/proxy/proxy.go | 11 +++++++---- 7 files changed, 41 insertions(+), 8 deletions(-) diff --git a/cmd/options.go b/cmd/options.go index 91fe9d7a8..b9fa7edca 100644 --- a/cmd/options.go +++ b/cmd/options.go @@ -89,3 +89,11 @@ func WithDebugLogging() Option { c.conf.DebugLogs = true } } + +// WithLazyRefresh configures the Proxy to refresh connection info on an +// as-needed basis when the cached copy has expired. +func WithLazyRefresh() Option { + return func(c *Command) { + c.conf.LazyRefresh = true + } +} diff --git a/cmd/options_test.go b/cmd/options_test.go index 01506f0d5..c3dc718f6 100644 --- a/cmd/options_test.go +++ b/cmd/options_test.go @@ -134,6 +134,18 @@ func TestCommandOptions(t *testing.T) { }, option: WithQuietLogging(), }, + { + desc: "with lazy refresh", + isValid: func(c *Command) error { + if !c.conf.LazyRefresh { + return errors.New( + "LazyRefresh was false, but should be true", + ) + } + return nil + }, + option: WithLazyRefresh(), + }, } for _, tc := range tcs { diff --git a/cmd/root.go b/cmd/root.go index 0cec25bf1..123e292fc 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -516,7 +516,10 @@ is the target account.`) address returned by the SQL Admin API. In most cases, this flag should not be used. Prefer default of public IP or use --private-ip instead.`) localFlags.BoolVar(&c.conf.LazyRefresh, "lazy-refresh", false, - `TODO`, + `Configure a lazy refresh where connection info is retrieved only if +the cached copy has expired. Use this setting in environments where the +CPU may be throttled and a background refresh cannot run reliably +(e.g., Cloud Run)`, ) localFlags.BoolVar(&c.conf.RunConnectionTest, "run-connection-test", false, `Runs a connection test diff --git a/cmd/root_test.go b/cmd/root_test.go index a3ca4ce98..027c2efff 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -412,6 +412,13 @@ func TestNewCommandArguments(t *testing.T) { Debug: true, }), }, + { + desc: "using the lazy refresh flag", + args: []string{"--lazy-refresh", "proj:region:inst"}, + want: withDefaults(&proxy.Config{ + LazyRefresh: true, + }), + }, { desc: "using the admin port flag", args: []string{"--admin-port", "7777", "proj:region:inst"}, diff --git a/go.mod b/go.mod index a65467dd6..7519fb63b 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/GoogleCloudPlatform/cloud-sql-proxy/v2 go 1.22 require ( - cloud.google.com/go/cloudsqlconn v1.8.1 + cloud.google.com/go/cloudsqlconn v1.8.2-0.20240415201134-931150f492cb contrib.go.opencensus.io/exporter/prometheus v0.4.2 contrib.go.opencensus.io/exporter/stackdriver v0.13.14 github.com/coreos/go-systemd/v22 v22.5.0 @@ -91,5 +91,3 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace cloud.google.com/go/cloudsqlconn => ../cloud-sql-go-connector diff --git a/go.sum b/go.sum index 44b0ddc18..235e2d745 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/cloudsqlconn v1.8.2-0.20240415201134-931150f492cb h1:QUt5wI7ufv6m4nEGYvqmW6N0g2mu95HCWozsruqVcVQ= +cloud.google.com/go/cloudsqlconn v1.8.2-0.20240415201134-931150f492cb/go.mod h1:BO9+K28yzyzDXKMtpmpEfhWqtLnmNvVpVtL02yFEegw= cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index 26e5f9c5b..e6ca8f72a 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -189,7 +189,10 @@ type Config struct { // users. AutoIP bool - // LazyRefresh TODO + // LazyRefresh configures the Go Connector to retrieve connection info + // lazily and as-needed. Otherwise, no background refresh cycle runs. This + // setting is useful in environments where the CPU may be throttled outside + // of a request context, e.g., Cloud Run. LazyRefresh bool // Instances are configuration for individual instances. Instance @@ -427,9 +430,9 @@ func (c *Config) DialerOptions(l cloudsql.Logger) ([]cloudsqlconn.Option, error) opts = append(opts, cloudsqlconn.WithQuotaProject(c.QuotaProject)) } - if c.LazyRefresh { - opts = append(opts, cloudsqlconn.WithLazyRefresh()) - } + if c.LazyRefresh { + opts = append(opts, cloudsqlconn.WithLazyRefresh()) + } return opts, nil }