mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-22 06:38:13 +00:00
Add cache operations via API.
This commit is contained in:
@@ -236,6 +236,11 @@ To do so - you need to enable the api by setting env variable `ENABLE_API=true`
|
|||||||
* `POST /api/user-ban` - ban the user from accessing the application
|
* `POST /api/user-ban` - ban the user from accessing the application
|
||||||
* `POST /api/user-unban` - unban the user from accessing the application
|
* `POST /api/user-unban` - unban the user from accessing the application
|
||||||
|
|
||||||
|
#### Cache operations
|
||||||
|
|
||||||
|
* `POST /api/cache-clear` - clear the cache
|
||||||
|
* `GET /api/cache-stats` - get the cache statistics ( hits, misses, size )
|
||||||
|
|
||||||
Both endpoints require the `user_id` parameter to be present in the request body and allow you to provide the reason for the ban.
|
Both endpoints require the `user_id` parameter to be present in the request body and allow you to provide the reason for the ban.
|
||||||
|
|
||||||
Example request:
|
Example request:
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ func enableApi() {
|
|||||||
api := apiserver.Group("/api")
|
api := apiserver.Group("/api")
|
||||||
api.Post("/user-ban", apiBanUser)
|
api.Post("/user-ban", apiBanUser)
|
||||||
api.Post("/user-unban", apiUnbanUser)
|
api.Post("/user-unban", apiUnbanUser)
|
||||||
|
api.Post("/cache-clear", apiClearCache)
|
||||||
|
api.Get("/cache-stats", apiCacheStats)
|
||||||
|
|
||||||
go periodicallyReloadBannedUsers()
|
go periodicallyReloadBannedUsers()
|
||||||
err := apiserver.Listen(fmt.Sprintf(":%d", cfg.Server.ApiPort))
|
err := apiserver.Listen(fmt.Sprintf(":%d", cfg.Server.ApiPort))
|
||||||
@@ -50,6 +52,21 @@ func checkIfUserIsBanned(c *fiber.Ctx, userID string) bool {
|
|||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func apiClearCache(c *fiber.Ctx) error {
|
||||||
|
cfg.Logger.Debug("Clearing cache via API", nil)
|
||||||
|
cfg.Cache.CacheClient.ClearCache()
|
||||||
|
cfg.Logger.Info("Cache cleared via API", nil)
|
||||||
|
c.Status(200).SendString("OK: cache cleared")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiCacheStats(c *fiber.Ctx) error {
|
||||||
|
stats := cfg.Cache.CacheClient.ShowStats()
|
||||||
|
cfg.Logger.Debug("Getting cache stats via API", map[string]interface{}{"stats": stats})
|
||||||
|
c.JSON(stats)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type apiBanUserRequest struct {
|
type apiBanUserRequest struct {
|
||||||
UserID string `json:"user_id"`
|
UserID string `json:"user_id"`
|
||||||
Reason string `json:"reason"`
|
Reason string `json:"reason"`
|
||||||
|
|||||||
Vendored
+33
-1
@@ -18,6 +18,8 @@ type Cache struct {
|
|||||||
globalTTL time.Duration
|
globalTTL time.Duration
|
||||||
compressPool sync.Pool
|
compressPool sync.Pool
|
||||||
decompressPool sync.Pool
|
decompressPool sync.Pool
|
||||||
|
cacheHits int
|
||||||
|
cacheMisses int
|
||||||
sync.RWMutex // Reintroduced to provide lock methods
|
sync.RWMutex // Reintroduced to provide lock methods
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,14 +77,16 @@ func (c *Cache) Get(key string) ([]byte, bool) {
|
|||||||
|
|
||||||
entry, ok := c.entries.Load(key)
|
entry, ok := c.entries.Load(key)
|
||||||
if !ok || entry.(CacheEntry).ExpiresAt.Before(time.Now()) {
|
if !ok || entry.(CacheEntry).ExpiresAt.Before(time.Now()) {
|
||||||
|
c.cacheMisses++
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
compressedValue := entry.(CacheEntry).Value
|
compressedValue := entry.(CacheEntry).Value
|
||||||
value, err := c.decompress(compressedValue)
|
value, err := c.decompress(compressedValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
c.cacheMisses++
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
c.cacheHits++
|
||||||
return value, true
|
return value, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +113,34 @@ func (c *Cache) CleanExpiredEntries() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CacheStats struct {
|
||||||
|
CachedQueries int `json:"cached_queries"`
|
||||||
|
CacheHits int `json:"cache_hits"`
|
||||||
|
CacheMisses int `json:"cache_misses"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) ShowStats() CacheStats {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
var count int
|
||||||
|
c.entries.Range(func(_, _ interface{}) bool {
|
||||||
|
count++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
cs := CacheStats{
|
||||||
|
CachedQueries: count,
|
||||||
|
CacheHits: c.cacheHits,
|
||||||
|
CacheMisses: c.cacheMisses,
|
||||||
|
}
|
||||||
|
return cs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) ClearCache() {
|
||||||
|
c.cacheHits = 0
|
||||||
|
c.cacheMisses = 0
|
||||||
|
c.entries = sync.Map{}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cache) compress(data []byte) ([]byte, error) {
|
func (c *Cache) compress(data []byte) ([]byte, error) {
|
||||||
w := c.compressPool.Get().(*gzip.Writer)
|
w := c.compressPool.Get().(*gzip.Writer)
|
||||||
defer c.compressPool.Put(w)
|
defer c.compressPool.Put(w)
|
||||||
|
|||||||
Vendored
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package libpack_cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assume that New function initializes the cache and it is defined somewhere in the libpack_cache package.
|
||||||
|
|
||||||
|
func BenchmarkCacheSet(b *testing.B) {
|
||||||
|
cache := New(30 * time.Second) // Initializing the cache with a TTL of 30 seconds
|
||||||
|
key := "benchmark-key"
|
||||||
|
value := []byte("benchmark-value")
|
||||||
|
|
||||||
|
b.ResetTimer() // Reset the timer to exclude the setup time from the benchmark
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
cache.Set(key, value, 5*time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCacheGet(b *testing.B) {
|
||||||
|
cache := New(30 * time.Second) // Initializing the cache
|
||||||
|
key := "benchmark-key"
|
||||||
|
value := []byte("benchmark-value")
|
||||||
|
cache.Set(key, value, 5*time.Second) // Pre-set a value to retrieve
|
||||||
|
|
||||||
|
b.ResetTimer() // Start timing
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, _ = cache.Get(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCacheExpire(b *testing.B) {
|
||||||
|
key := "benchmark-expire-key"
|
||||||
|
value := []byte("benchmark-value")
|
||||||
|
ttl := 5 * time.Millisecond // Setting a short TTL for quick expiration
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
cache := New(30 * time.Second)
|
||||||
|
cache.Set(key, value, ttl)
|
||||||
|
time.Sleep(ttl) // Wait for the key to expire
|
||||||
|
_, _ = cache.Get(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCacheStats(b *testing.B) {
|
||||||
|
cache := New(30 * time.Second) // Initializing the cache
|
||||||
|
key := "benchmark-key"
|
||||||
|
value := []byte("benchmark-value")
|
||||||
|
cache.Set(key, value, 5*time.Second) // Pre-set a value to retrieve
|
||||||
|
cache.Get(key)
|
||||||
|
}
|
||||||
Vendored
+33
@@ -110,3 +110,36 @@ func (suite *CacheTestSuite) Test_CacheExpire() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *CacheTestSuite) Test_CacheStats() {
|
||||||
|
cache := New(30 * time.Second)
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
cache_value string
|
||||||
|
ttl time.Duration
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test1",
|
||||||
|
cache_value: "test1-123",
|
||||||
|
ttl: 2 * time.Second,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test2",
|
||||||
|
cache_value: "test2-123",
|
||||||
|
ttl: 5 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
suite.T().Run(tt.name, func(t *testing.T) {
|
||||||
|
cache.Set(tt.name, []byte(tt.name), tt.ttl)
|
||||||
|
c, ok := cache.Get(tt.name)
|
||||||
|
suite.Equal(true, ok)
|
||||||
|
suite.Equal(tt.name, string(c))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
cache.Get("non-existent-non-cached-key")
|
||||||
|
stats := cache.ShowStats()
|
||||||
|
suite.Equal(2, stats.CacheHits, "CacheHits")
|
||||||
|
suite.Equal(1, stats.CacheMisses, "CacheMisses")
|
||||||
|
suite.Equal(2, stats.CachedQueries, "CachedQueries")
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user