Skip to content

Commit

Permalink
Support garbage collection of expired tokens from cache
Browse files Browse the repository at this point in the history
Signed-off-by: Han Verstraete (OpenFaaS Ltd) <[email protected]>
  • Loading branch information
welteki committed May 30, 2024
1 parent 6b9d6a4 commit 343aee3
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 1 deletion.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,21 @@ ts := sdk.NewClientCredentialsTokenSource(clientID, clientSecret, tokenURL, scop
client := sdk.NewClientWithOpts(gatewayURL, http.DefaultClient, sdk.WithFunctionTokenSource(ts))
```

Optionally a `TokenCache` can be configured to cache function access tokens and prevent the client from having to do a token exchange each time a function is invoked.

```go
fnTokenCache := sdk.NewMemoryTokenCache()
// Start garbage collection to remove expired tokens from the cache.
go fnTokenCache.StartGC(context.Background(), time.Second*10)

client := sdk.NewClientWithOpts(
gatewayUrl,
httpClient,
sdk.WithAuthentication(auth),
sdk.WithFunctionTokenCache(fnTokenCache),
)
```

## License

License: MIT
41 changes: 40 additions & 1 deletion tokencache.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,40 @@
package sdk

import "sync"
import (
"context"
"sync"
"time"
)

type TokenCache interface {
Get(key string) (*Token, bool)
Set(key string, token *Token)
}

// MemoryTokenCache is a basic in-memory token cache implementation.
type MemoryTokenCache struct {
tokens map[string]*Token

lock sync.RWMutex
}

// NewMemoryTokenCache creates a new in memory token cache instance.
func NewMemoryTokenCache() *MemoryTokenCache {
return &MemoryTokenCache{
tokens: map[string]*Token{},
}
}

// Set adds or updates a token with the given key in the cache.
func (c *MemoryTokenCache) Set(key string, token *Token) {
c.lock.Lock()
defer c.lock.Unlock()

c.tokens[key] = token
}

// Get retrieves the token associated with the given key from the cache. The bool
// return value will be false if no matching key is found, and true otherwise.
func (c *MemoryTokenCache) Get(key string) (*Token, bool) {
c.lock.RLock()
token, ok := c.tokens[key]
Expand All @@ -41,3 +50,33 @@ func (c *MemoryTokenCache) Get(key string) (*Token, bool) {

return token, ok
}

// StartGC starts garbage collection of expired tokens.
func (c *MemoryTokenCache) StartGC(ctx context.Context, gcInterval time.Duration) {
if gcInterval <= 0 {
return
}

ticker := time.NewTicker(gcInterval)

for {
select {
case <-ticker.C:
c.clearExpired()
case <-ctx.Done():
ticker.Stop()
return
}
}
}

// clearExpired removes all expired tokens from the cache.
func (c *MemoryTokenCache) clearExpired() {
for key, token := range c.tokens {
if token.Expired() {
c.lock.Lock()
delete(c.tokens, key)
c.lock.Unlock()
}
}
}

0 comments on commit 343aee3

Please sign in to comment.