okta-sdk-java icon indicating copy to clipboard operation
okta-sdk-java copied to clipboard

Cache configuration by resource seems to be unused by ApiClient

Open sinha-abhi opened this issue 10 months ago • 4 comments

Describe the bug?

Cache manager does not seem to use the resource based cache when creating a cache manager for the api client like:

val cacheManager =
  Caches
    .newCacheManager
    .withCache(
      forResource(classOf[User]) // user specific cache settings
        .withTimeToLive(30L, TimeUnit.SECONDS)
    )
    .build

val client =
  Clients
    .builder
    .setCacheManager(cacheManager)
    .setOrgUrl(<org url>)
    .setClientCredentials(new TokenClientCredentials(<token>))
    .build

Instead, the client uses the "default" cache that has no ttl/tti set.

What is expected to happen?

The client uses the configured cache for any com.okta.sdk.resource.model.User entries with the ttl specified.

What is the actual behavior?

Any users are inserted into the default cache that has no ttl/tti and the configured cache is ignored/unused.

It seems like the ApiClient always asks for the default cache though, so maybe this is just a usage error?

Reproduction Steps?

  • create a new api client with a cache configured for com.okta.sdk.resource.model.User
  • use okta api client to get a user
  • user gets inserted into default cache, instead of configured cache
  • user outlives the ttl defined on the configured cache, and stays in cache indefinitely because no ttl/tti is specified on the default cache

Additional Information?

printing cache contents every 15 seconds with ttl for User type configued to 30 seconds. there's some added information (patch below). by the last entry, you can see that the resource outlived the 30 second ttl

cache stats 2025-02-18T14:55:39.311259Z:
{
  "cacheCount": 0,
  "defaultTimeToLive": "indefinite",
  "defaultTimeToIdle": "indefinite",
  "cacheConfigs": "com.okta.sdk.resource.model.User",
  "caches": []

}

2025-02-18 09:55:39,433 [main] DEBUG com.okta.sdk.impl.cache.DefaultCacheManager - Creating cache 'default'

cache stats 2025-02-18T14:55:54.316008Z:
{
  "cacheCount": 1,
  "defaultTimeToLive": "indefinite",
  "defaultTimeToIdle": "indefinite",
  "cacheConfigs": "com.okta.sdk.resource.model.User",
  "caches": [
    {
      "name": "default",
      "size": 0,
      "accessCount": 0,
      "hitCount": 0,
      "missCount": 0,
      "hitRatio": 0.0
      "contents": [

      ]
    }
  ]
}

cache stats 2025-02-18T14:56:09.312429Z:
{
  "cacheCount": 1,
  "defaultTimeToLive": "indefinite",
  "defaultTimeToIdle": "indefinite",
  "cacheConfigs": "com.okta.sdk.resource.model.User",
  "caches": [
    {
      "name": "default",
      "size": 1,
      "accessCount": 1,
      "hitCount": 0,
      "missCount": 1,
      "hitRatio": 0.0
      "contents": [
        {
          "key": "https://<okta_org>/api/v1/users/<okta-id>"
          "resourceType": "com.okta.sdk.resource.model.User"
          "insertedAt": "2025-02-18T14:55:57.308Z"
        }
      ]
    }
  ]
}

cache stats 2025-02-18T14:56:54.311502Z:
{
  "cacheCount": 1,
  "defaultTimeToLive": "indefinite",
  "defaultTimeToIdle": "indefinite",
  "cacheConfigs": "com.okta.sdk.resource.model.User",
  "caches": [
    {
      "name": "default",
      "size": 1,
      "accessCount": 1,
      "hitCount": 0,
      "missCount": 1,
      "hitRatio": 0.0
      "contents": [
        {
          "key": "https://<okta_org>/api/v1/users/<okta-id>"
          "resourceType": "com.okta.sdk.resource.model.User"
          "insertedAt": "2025-02-18T14:55:57.308Z"
        }
      ]
    }
  ]
}

patch to get extra information in cache details:

diff --git a/impl/src/main/java/com/okta/sdk/impl/cache/DefaultCache.java b/impl/src/main/java/com/okta/sdk/impl/cache/DefaultCache.java
index a319494da8b..735911b9ed2 100644
--- a/impl/src/main/java/com/okta/sdk/impl/cache/DefaultCache.java
+++ b/impl/src/main/java/com/okta/sdk/impl/cache/DefaultCache.java
@@ -23,8 +23,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.time.Duration;
+import java.time.Instant;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
 
 /**
  * A {@code DefaultCache} is a {@link Cache Cache} implementation that uses a backing {@link Map} instance to store
@@ -343,15 +345,30 @@ public class DefaultCache<K, V> implements Cache<K, V> {
         return this.name;
     }
 
+    private String entryToString(Map.Entry<K, Entry<V>> e) {
+        return new StringBuilder("        {\n          \"key\": \"").append(e.getKey()).append("\"\n")
+            .append("          \"resourceType\": \"").append(e.getValue().getValue().getClass().getName()).append("\"\n")
+            .append("          \"insertedAt\": \"").append(Instant.ofEpochMilli(e.getValue().getCreationTimeMillis())).append("\"\n")
+            .append("        }")
+            .toString();
+    }
+
     public String toString() {
+        String contents =
+            map.entrySet()
+                .stream()
+                .map(this::entryToString)
+                .collect(Collectors.joining(",\n"));
+
         return new StringBuilder("    {\n      \"name\": \"").append(name).append("\",\n")
-                .append("      \"size\": ").append(map.size()).append(",\n")
-                .append("      \"accessCount\": ").append(getAccessCount()).append(",\n")
-                .append("      \"hitCount\": ").append(getHitCount()).append(",\n")
-                .append("      \"missCount\": ").append(getMissCount()).append(",\n")
-                .append("      \"hitRatio\": ").append(getHitRatio()).append("\n")
-                .append("    }")
-                .toString();
+            .append("      \"size\": ").append(map.size()).append(",\n")
+            .append("      \"accessCount\": ").append(getAccessCount()).append(",\n")
+            .append("      \"hitCount\": ").append(getHitCount()).append(",\n")
+            .append("      \"missCount\": ").append(getMissCount()).append(",\n")
+            .append("      \"hitRatio\": ").append(getHitRatio()).append("\n")
+            .append("      \"contents\": ").append("[\n").append(contents).append("\n      ]\n")
+            .append("    }")
+            .toString();
     }
 
     /**
diff --git a/impl/src/main/java/com/okta/sdk/impl/cache/DefaultCacheManager.java b/impl/src/main/java/com/okta/sdk/impl/cache/DefaultCacheManager.java
index fb6eff33996..3b2d3a019f3 100644
--- a/impl/src/main/java/com/okta/sdk/impl/cache/DefaultCacheManager.java
+++ b/impl/src/main/java/com/okta/sdk/impl/cache/DefaultCacheManager.java
@@ -246,6 +246,7 @@ public class DefaultCacheManager implements CacheManager {
                 .append("  \"cacheCount\": ").append(caches.size()).append(",\n")
                 .append("  \"defaultTimeToLive\": \"").append(toString(defaultTimeToLive)).append("\",\n")
                 .append("  \"defaultTimeToIdle\": \"").append(toString(defaultTimeToIdle)).append("\",\n")
+                .append("  \"cacheConfigs\": \"").append(String.join(", ", configs.keySet())).append("\",\n")
                 .append("  \"caches\": [");
 
         if (!caches.isEmpty()) {

Java Version

openjdk version "11.0.24" 2024-07-16 LTS OpenJDK Runtime Environment Zulu11.74+15-CA (build 11.0.24+8-LTS) OpenJDK 64-Bit Server VM Zulu11.74+15-CA (build 11.0.24+8-LTS, mixed mode)

We use scala: Scala code runner version 2.12.20 -- Copyright 2002-2024, LAMP/EPFL and Lightbend, Inc.

SDK Version

13.0.0

OS version

Darwin ICN-XYN6FYKFCR 24.2.0 Darwin Kernel Version 24.2.0: Fri Dec 6 19:01:59 PST 2024; root:xnu-11215.61.5~2/RELEASE_ARM64_T6000 arm64

sinha-abhi avatar Feb 18 '25 15:02 sinha-abhi

Thanks for reporting this!

@prachi-okta can you please help take a look?

arvindkrishnakumar-okta avatar Feb 18 '25 15:02 arvindkrishnakumar-okta

Hi @sinha-abhi, is it possible for you to publish your branch so I can take a look? Thanks.

prachi-okta avatar May 12 '25 05:05 prachi-okta

I don't have a branch, but you should be able to just apply the patch I posted above

sinha-abhi avatar Jun 02 '25 10:06 sinha-abhi

@prachi-okta @arvindkrishnakumar-okta have you guys gotten a chance to look? has this been fixed in newer versions?

sinha-abhi avatar Jul 01 '25 19:07 sinha-abhi