Skip to content

Commit 371fe13

Browse files
authored
feat: bust the tenant cache on the token expiry (#1279)
* feat: bust the cache on token expiry * fix: rename ExpirationDate to Expiry
1 parent 009ff5f commit 371fe13

File tree

5 files changed

+413
-309
lines changed

5 files changed

+413
-309
lines changed

internal/tenants/manager.go

+22-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type tenantInfo struct {
2525
tenant *sm.Tenant
2626
}
2727

28-
// NewTenantManager creates a new tenant manager that is able to
28+
// NewManager creates a new tenant manager that is able to
2929
// retrieve tenants from the remote API using the specified
3030
// tenantsClient or receive them over the provided tenantCh channel. It
3131
// will keep them for a duration no longer than `timeout`.
@@ -57,6 +57,19 @@ func (tm *Manager) run(ctx context.Context) {
5757
}
5858
}
5959

60+
// calculateValidUntil determines the expiration time for a tenant based on the timeout
61+
// and the secret store expiration date (if set), returning the earlier of the two.
62+
func (tm *Manager) calculateValidUntil(tenant *sm.Tenant) time.Time {
63+
validUntil := time.Now().Add(tm.timeout)
64+
if tenant.SecretStore != nil && tenant.SecretStore.Expiry > 0 {
65+
expirationTime := time.Unix(0, int64(tenant.SecretStore.Expiry*1e9))
66+
if expirationTime.Before(validUntil) {
67+
validUntil = expirationTime
68+
}
69+
}
70+
return validUntil
71+
}
72+
6073
func (tm *Manager) updateTenant(tenant sm.Tenant) {
6174
tm.tenantsMutex.Lock()
6275

@@ -87,7 +100,10 @@ func (tm *Manager) updateTenant(tenant sm.Tenant) {
87100

88101
info.mutex.Lock()
89102
if info.tenant == nil || info.tenant.Modified < tenant.Modified {
90-
info.validUntil = time.Now().Add(tm.timeout)
103+
// Set validUntil to the earlier of:
104+
// - Now + timeout
105+
// - Secret store expiration date (if set)
106+
info.validUntil = tm.calculateValidUntil(&tenant)
91107
info.tenant = &tenant
92108
}
93109
info.mutex.Unlock()
@@ -130,7 +146,10 @@ func (tm *Manager) GetTenant(ctx context.Context, req *sm.TenantInfo) (*sm.Tenan
130146

131147
// If tenant was retrieved from the API, update it in the cache
132148
if err == nil {
133-
info.validUntil = time.Now().Add(tm.timeout)
149+
// Set validUntil to the earlier of:
150+
// - Now + timeout
151+
// - Secret store expiration date (if set)
152+
info.validUntil = tm.calculateValidUntil(tenant)
134153
info.tenant = tenant
135154
}
136155

internal/tenants/manager_test.go

+62
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,65 @@ func TestTenantManagerGetTenant(t *testing.T) {
161161
require.Equal(t, 1, tc.requestCount[t3.Id])
162162
require.Equal(t, t3, *tenant)
163163
}
164+
165+
func TestCalculateValidUntil(t *testing.T) {
166+
now := time.Now()
167+
timeout := 5 * time.Minute
168+
timeWindow := 100 * time.Millisecond
169+
170+
tests := map[string]struct {
171+
tenant *sm.Tenant
172+
expectedBefore time.Time
173+
expectedAfter time.Time
174+
}{
175+
"no secret store": {
176+
tenant: &sm.Tenant{},
177+
expectedBefore: now.Add(timeout).Add(timeWindow),
178+
expectedAfter: now.Add(timeout).Add(-timeWindow),
179+
},
180+
"secret store with no expiration": {
181+
tenant: &sm.Tenant{
182+
SecretStore: &sm.SecretStore{},
183+
},
184+
expectedBefore: now.Add(timeout).Add(timeWindow),
185+
expectedAfter: now.Add(timeout).Add(-timeWindow),
186+
},
187+
"secret store with earlier expiration": {
188+
tenant: &sm.Tenant{
189+
SecretStore: &sm.SecretStore{
190+
Token: "token",
191+
Expiry: float64(now.Add(2*time.Minute).UnixNano()) / 1e9,
192+
},
193+
},
194+
expectedBefore: now.Add(2 * time.Minute).Add(timeWindow),
195+
expectedAfter: now.Add(2 * time.Minute).Add(-timeWindow),
196+
},
197+
"secret store with later expiration": {
198+
tenant: &sm.Tenant{
199+
SecretStore: &sm.SecretStore{
200+
Token: "token",
201+
Expiry: float64(now.Add(10*time.Minute).UnixNano()) / 1e9,
202+
},
203+
},
204+
expectedBefore: now.Add(timeout).Add(timeWindow),
205+
expectedAfter: now.Add(timeout).Add(-timeWindow),
206+
},
207+
}
208+
209+
for name, tt := range tests {
210+
t.Run(name, func(t *testing.T) {
211+
tm := &Manager{
212+
timeout: timeout,
213+
}
214+
215+
validUntil := tm.calculateValidUntil(tt.tenant)
216+
217+
if validUntil.After(tt.expectedBefore) {
218+
t.Errorf("validUntil %v is after expected time %v", validUntil, tt.expectedBefore)
219+
}
220+
if validUntil.Before(tt.expectedAfter) {
221+
t.Errorf("validUntil %v is before expected time %v", validUntil, tt.expectedAfter)
222+
}
223+
})
224+
}
225+
}
185 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)