System Cache Config fields

This commit is contained in:
simonredfern 2026-01-01 04:34:55 +01:00
parent 5e00e012db
commit f365523360
3 changed files with 89 additions and 43 deletions

View File

@ -667,8 +667,8 @@ trait APIMethods600 {
"Get Cache Configuration",
"""Returns cache configuration information including:
|
|- Available cache providers (Redis, In-Memory)
|- Redis connection details (URL, port, SSL)
|- Redis status: availability, connection details (URL, port, SSL)
|- In-memory cache status: availability and current size
|- Instance ID and environment
|- Global cache namespace prefix
|
@ -678,21 +678,15 @@ trait APIMethods600 {
|""",
EmptyBody,
CacheConfigJsonV600(
providers = List(
CacheProviderConfigJsonV600(
provider = "redis",
enabled = true,
url = Some("127.0.0.1"),
port = Some(6379),
use_ssl = Some(false)
),
CacheProviderConfigJsonV600(
provider = "in_memory",
enabled = true,
url = None,
port = None,
use_ssl = None
)
redis_status = RedisCacheStatusJsonV600(
available = true,
url = "127.0.0.1",
port = 6379,
use_ssl = false
),
in_memory_status = InMemoryCacheStatusJsonV600(
available = true,
current_size = 42
),
instance_id = "obp",
environment = "dev",
@ -738,6 +732,9 @@ trait APIMethods600 {
| - "memory": Keys stored in in-memory cache
| - "both": Keys in both locations (indicates a BUG - should never happen)
| - "unknown": No keys found, storage location cannot be determined
|- TTL info: Sampled TTL information from actual keys
| - Shows actual TTL values from up to 5 sample keys
| - Format: "123s" (fixed), "range 60s to 3600s (avg 1800s)" (variable), "no expiry" (persistent)
|- Total key count across all namespaces
|- Redis availability status
|
@ -755,7 +752,8 @@ trait APIMethods600 {
key_count = 42,
description = "Rate limit call counters",
category = "Rate Limiting",
storage_location = "redis"
storage_location = "redis",
ttl_info = "range 60s to 86400s (avg 3600s)"
),
CacheNamespaceInfoJsonV600(
namespace_id = "rd_localised",
@ -764,7 +762,8 @@ trait APIMethods600 {
key_count = 128,
description = "Localized resource docs",
category = "API Documentation",
storage_location = "redis"
storage_location = "redis",
ttl_info = "3600s"
)
),
total_keys = 170,

View File

@ -268,16 +268,21 @@ case class InvalidatedCacheNamespaceJsonV600(
status: String
)
case class CacheProviderConfigJsonV600(
provider: String,
enabled: Boolean,
url: Option[String],
port: Option[Int],
use_ssl: Option[Boolean]
case class RedisCacheStatusJsonV600(
available: Boolean,
url: String,
port: Int,
use_ssl: Boolean
)
case class InMemoryCacheStatusJsonV600(
available: Boolean,
current_size: Long
)
case class CacheConfigJsonV600(
providers: List[CacheProviderConfigJsonV600],
redis_status: RedisCacheStatusJsonV600,
in_memory_status: InMemoryCacheStatusJsonV600,
instance_id: String,
environment: String,
global_prefix: String
@ -290,7 +295,8 @@ case class CacheNamespaceInfoJsonV600(
key_count: Int,
description: String,
category: String,
storage_location: String
storage_location: String,
ttl_info: String
)
case class CacheInfoJsonV600(
@ -1120,21 +1126,17 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
import code.api.Constant
import net.liftweb.util.Props
val redisProvider = CacheProviderConfigJsonV600(
provider = "redis",
enabled = true,
url = Some(Redis.url),
port = Some(Redis.port),
use_ssl = Some(Redis.useSsl)
)
val redisIsReady = try {
Redis.isRedisReady
} catch {
case _: Throwable => false
}
val inMemoryProvider = CacheProviderConfigJsonV600(
provider = "in_memory",
enabled = true,
url = None,
port = None,
use_ssl = None
)
val inMemorySize = try {
InMemory.underlyingGuavaCache.size()
} catch {
case _: Throwable => 0L
}
val instanceId = code.api.util.APIUtil.getPropsValue("api_instance_id").getOrElse("obp")
val environment = Props.mode match {
@ -1145,8 +1147,21 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
case _ => "unknown"
}
val redisStatus = RedisCacheStatusJsonV600(
available = redisIsReady,
url = Redis.url,
port = Redis.port,
use_ssl = Redis.useSsl
)
val inMemoryStatus = InMemoryCacheStatusJsonV600(
available = inMemorySize >= 0,
current_size = inMemorySize
)
CacheConfigJsonV600(
providers = List(redisProvider, inMemoryProvider),
redis_status = redisStatus,
in_memory_status = inMemoryStatus,
instance_id = instanceId,
environment = environment,
global_prefix = Constant.getGlobalCacheNamespacePrefix
@ -1156,6 +1171,7 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
def createCacheInfoJsonV600(): CacheInfoJsonV600 = {
import code.api.cache.{Redis, InMemory}
import code.api.Constant
import code.api.JedisMethod
val namespaceDescriptions = Map(
Constant.CALL_COUNTER_NAMESPACE -> ("Rate limit call counters", "Rate Limiting"),
@ -1183,10 +1199,33 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
var redisKeyCount = 0
var memoryKeyCount = 0
var storageLocation = "unknown"
var ttlInfo = "no keys to sample"
try {
redisKeyCount = Redis.countKeys(pattern)
totalKeys += redisKeyCount
// Sample keys to get TTL information
if (redisKeyCount > 0) {
val sampleKeys = Redis.scanKeys(pattern).take(5)
val ttls = sampleKeys.flatMap { key =>
Redis.use(JedisMethod.TTL, key, None, None).map(_.toLong)
}
if (ttls.nonEmpty) {
val minTtl = ttls.min
val maxTtl = ttls.max
val avgTtl = ttls.sum / ttls.length.toLong
ttlInfo = if (minTtl == maxTtl) {
if (minTtl == -1) "no expiry"
else if (minTtl == -2) "keys expired or missing"
else s"${minTtl}s"
} else {
s"range ${minTtl}s to ${maxTtl}s (avg ${avgTtl}s)"
}
}
}
} catch {
case _: Throwable =>
redisAvailable = false
@ -1195,6 +1234,10 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
try {
memoryKeyCount = InMemory.countKeys(pattern)
totalKeys += memoryKeyCount
if (memoryKeyCount > 0 && redisKeyCount == 0) {
ttlInfo = "in-memory (no TTL in Guava cache)"
}
} catch {
case _: Throwable =>
// In-memory cache error (shouldn't happen, but handle gracefully)
@ -1203,6 +1246,7 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
// Determine storage based on where keys actually exist
val keyCount = if (redisKeyCount > 0 && memoryKeyCount > 0) {
storageLocation = "both"
ttlInfo = s"redis: ${ttlInfo}, memory: in-memory cache"
redisKeyCount + memoryKeyCount
} else if (redisKeyCount > 0) {
storageLocation = "redis"
@ -1225,7 +1269,8 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
key_count = keyCount,
description = description,
category = category,
storage_location = storageLocation
storage_location = storageLocation,
ttl_info = ttlInfo
)
}

View File

@ -158,6 +158,8 @@ class CacheEndpointsTest extends V600ServerSetup {
namespace.category should not be empty
namespace.storage_location should not be empty
namespace.storage_location should (equal("redis") or equal("memory") or equal("both") or equal("unknown"))
namespace.ttl_info should not be empty
namespace.ttl_info shouldBe a[String]
}
}
}