Skip to content

Commit 77cd230

Browse files
authored
Increase lease timeout for sso operations and provide arrow-adbc configuration hook for future adjustments (#13)
* Increase timeout to 30s to support headless sso and ide sso * Add hooks for configuring lease timeouts without disturbing singleton design. * Change timeout to millis. No need to worry about cpu alignment. single entrypoint to value through setter and getter normalizes. Decisions on how to handle data made explicit for future readers.
1 parent 34bc225 commit 77cd230

3 files changed

Lines changed: 82 additions & 15 deletions

File tree

authexternalbrowser.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,8 @@ func doAuthenticateByExternalBrowser(
340340
func waitForSamlResponse(ctx context.Context, lease *Lease, l net.Listener, application string) (string, error) {
341341
encodedChan := make(chan string, 1)
342342
errChan := make(chan error, 1)
343-
ticker := time.NewTicker(leaseTTL / 2)
343+
ttl := leaseTTL()
344+
ticker := time.NewTicker(ttl / 2)
344345

345346
go func() {
346347
conn, err := l.Accept()
@@ -399,7 +400,7 @@ func waitForSamlResponse(ctx context.Context, lease *Lease, l net.Listener, appl
399400
for {
400401
select {
401402
case <-ticker.C:
402-
lease.Renew(leaseTTL)
403+
lease.Renew(ttl)
403404
case s := <-encodedChan:
404405
ticker.Stop()
405406
return s, nil

lease.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"os"
1313
"path/filepath"
1414
"strconv"
15+
"sync/atomic"
1516
"time"
1617
)
1718

@@ -63,19 +64,38 @@ func (lease *Lease) Release() error {
6364
//
6465
// [1] https://en.wikipedia.org/wiki/Lease_(computer_science)
6566
type LeaseHandler struct {
66-
path string // absolute path to the lease file
67-
dir string // directory where the lease file is stored
68-
timeout time.Duration // how long to keep trying to acquire or renew a lease
67+
path string // absolute path to the lease file
68+
dir string // directory where the lease file is stored
69+
timeoutMillis int32 // atomic; how long to keep trying to acquire or renew a lease
6970
}
7071

7172
func NewLeaseHandler(path string, timeout time.Duration) (*LeaseHandler, error) {
7273
abspath, err := filepath.Abs(path)
7374
if err != nil {
7475
return nil, fmt.Errorf("lease: %w", err)
7576
}
76-
timeout = max(timeout, MinLeaseOperationTimeout)
7777
dir := filepath.Dir(abspath)
78-
return &LeaseHandler{path: abspath, dir: dir, timeout: timeout}, nil
78+
h := &LeaseHandler{path: abspath, dir: dir}
79+
h.SetTimeout(timeout)
80+
return h, nil
81+
}
82+
83+
// Normalize timeout to atomic-friendly i32 and store atomically
84+
// Clamp to prevent wraparound. Truncate to ms.
85+
func (l *LeaseHandler) SetTimeout(d time.Duration) {
86+
if d < MinLeaseOperationTimeout {
87+
d = MinLeaseOperationTimeout
88+
}
89+
ms := d.Milliseconds()
90+
if ms > math.MaxInt32 {
91+
ms = math.MaxInt32
92+
}
93+
atomic.StoreInt32(&l.timeoutMillis, int32(ms))
94+
}
95+
96+
func (l *LeaseHandler) getTimeout() time.Duration {
97+
ms := atomic.LoadInt32(&l.timeoutMillis)
98+
return time.Duration(ms) * time.Millisecond
7999
}
80100

81101
func randomLeaseId() (string, error) {
@@ -251,7 +271,7 @@ func (l *LeaseHandler) Acquire(ttl time.Duration) (*Lease, error) {
251271

252272
base := time.Duration(0)
253273
m := gracePeriod
254-
deadline := time.Now().Add(l.timeout)
274+
deadline := time.Now().Add(l.getTimeout())
255275
for time.Now().Before(deadline) {
256276
data, err := l.read(base, m, min(deadline.Sub(time.Now())/2, maxPollInterval))
257277
base, m = nextWait(base, m)
@@ -287,15 +307,15 @@ func (l *LeaseHandler) Acquire(ttl time.Duration) (*Lease, error) {
287307
return &Lease{id: newLeaseId, expiry: expiry, handler: l}, nil
288308
}
289309

290-
return nil, fmt.Errorf("timed out trying to acquire lease after %s: %s", l.timeout, l.path)
310+
return nil, fmt.Errorf("timed out trying to acquire lease after %s: %s", l.getTimeout(), l.path)
291311
}
292312

293313
func (l *LeaseHandler) renew(leaseId *string, ttl time.Duration, currentExpiry time.Time) (time.Time, error) {
294314
// fmt.Fprintf(os.Stdout, "[%v] Renew('%s')\n", routine.Goid(), *leaseId)
295315

296316
base := time.Duration(0)
297317
m := time.Duration(0)
298-
deadline := time.Now().Add(l.timeout)
318+
deadline := time.Now().Add(l.getTimeout())
299319
for time.Now().Before(deadline) {
300320
wait(base, m, min(deadline.Sub(time.Now())/2, maxPollInterval))
301321
base, m = nextWait(base, m)

secure_storage_manager.go

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,64 @@ import (
1111
"strconv"
1212
"strings"
1313
"sync"
14+
"sync/atomic"
1415
"time"
1516
)
1617

1718
const (
18-
leaseTTL = 10 * time.Second
19-
leaseOperationTimeout = 60 * time.Second
19+
// accessed through getters that provide an override hook, do not use directly
20+
_defaultLeaseTTL = 30 * time.Second
21+
_defaultLeaseOperationTimeout = 90 * time.Second
2022

2123
credCacheDirEnv = "SF_TEMPORARY_CREDENTIAL_CACHE_DIR"
2224
credLeaseFileName = "credential_cache.lease"
2325
credCacheFileName = "credential_cache_v1.json"
2426
)
2527

28+
// --- EvalOnce hook to configure lease semantics ------------------------
29+
30+
var (
31+
_cfgOnce sync.Once
32+
_overrideTTL atomic.Value // stores time.Duration
33+
_overrideTimeout atomic.Value // ditto
34+
)
35+
36+
// Call once per process.
37+
//
38+
// Ignore 0 values and keep defaults
39+
// Propogate changes to singleton credentialsStorage's LeaseHandler
40+
func ConfigureLeaseOnce(ttl, timeout time.Duration) {
41+
_cfgOnce.Do(func() {
42+
if ttl > 0 {
43+
_overrideTTL.Store(ttl)
44+
}
45+
if timeout > 0 {
46+
_overrideTimeout.Store(timeout)
47+
// warn: will fail if of other type but this is not dbt's use
48+
// of the api
49+
if fb, ok := credentialsStorage.(*fileBasedSecureStorageManager); ok && fb.leaseHandler != nil {
50+
fb.leaseHandler.SetTimeout(timeout)
51+
}
52+
}
53+
})
54+
}
55+
56+
func leaseTTL() time.Duration {
57+
if v := _overrideTTL.Load(); v != nil {
58+
return v.(time.Duration)
59+
}
60+
return _defaultLeaseTTL
61+
}
62+
63+
func leaseOperationTimeout() time.Duration {
64+
if v := _overrideTimeout.Load(); v != nil {
65+
return v.(time.Duration)
66+
}
67+
return _defaultLeaseOperationTimeout
68+
}
69+
70+
// --- CacheDir resolution ------------------------
71+
2672
type cacheDirConf struct {
2773
envVar string
2874
pathSegments []string
@@ -98,7 +144,7 @@ func newFileBasedSecureStorageManager() (*fileBasedSecureStorageManager, error)
98144
if err != nil {
99145
return nil, err
100146
}
101-
leaseHandler, err := NewLeaseHandler(filepath.Join(credDirPath, credLeaseFileName), leaseOperationTimeout)
147+
leaseHandler, err := NewLeaseHandler(filepath.Join(credDirPath, credLeaseFileName), leaseOperationTimeout())
102148
if err != nil {
103149
return nil, err
104150
}
@@ -173,11 +219,11 @@ func (ssm *fileBasedSecureStorageManager) getTokens(data map[string]any) map[str
173219
}
174220

175221
func (ssm *fileBasedSecureStorageManager) acquireLease() (*Lease, error) {
176-
return ssm.leaseHandler.Acquire(leaseTTL)
222+
return ssm.leaseHandler.Acquire(leaseTTL())
177223
}
178224

179225
func (ssm *fileBasedSecureStorageManager) withCacheFile(lease *Lease, action func(*os.File) error) error {
180-
err := lease.Renew(leaseTTL / 2)
226+
err := lease.Renew(leaseTTL() / 2)
181227
if err != nil {
182228
logger.Warnf("Unable to lease cache. %v", err)
183229
return err

0 commit comments

Comments
 (0)