@@ -121,8 +121,10 @@ public class ApproovService {
121121 private static long cachedFailureTimeMs = 0 ;
122122 private static long failureCacheTtlMs = 500 ; // 0.5 seconds default
123123
124- // Gate lock for the SDK fetch call. When the failure cache is empty, only ONE thread
125- // enters the SDK; all others wait on this lock and then re-check the cache.
124+ // Gate lock for the SDK fetch call. When the service-layer failure cache is empty,
125+ // only ONE thread enters the SDK; all others wait on this lock and then re-check
126+ // the failure cache. This collapses concurrent failure storms that the SDK does
127+ // not cache, while successful fetches use the SDK's own cache/fast path.
126128 // This is separate from failureCacheLock to avoid holding the cache lock during
127129 // the potentially long (~1-3s) SDK network call.
128130 private static final Object fetchGateLock = new Object ();
@@ -256,7 +258,8 @@ public static void setFailureCacheTtlMs(long ttlMs) {
256258 }
257259
258260 /**
259- * Caches a failure result. Only failure statuses are cached; success is never cached.
261+ * Caches a failure result. Only failure statuses are cached by this service layer;
262+ * success caching is handled by the SDK.
260263 */
261264 static void cacheFailureIfNeeded (Approov .TokenFetchResult result ) {
262265 switch (result .getStatus ()) {
@@ -271,7 +274,7 @@ static void cacheFailureIfNeeded(Approov.TokenFetchResult result) {
271274 }
272275 break ;
273276 default :
274- // Success and other statuses are never cached
277+ // Success and other statuses are not cached by this service layer.
275278 break ;
276279 }
277280 }
@@ -284,8 +287,9 @@ static void cacheFailureIfNeeded(Approov.TokenFetchResult result) {
284287 * wait, then re-check the cache. This collapses N concurrent SDK calls into 1 when
285288 * the platform is in a failure state (MITM, no network, etc.).
286289 * <p>
287- * On the happy path (SDK returns a valid token), no caching occurs and the gate
288- * is released immediately — subsequent threads each get their own unique token.
290+ * On the happy path (SDK returns a valid token), this service layer does not
291+ * cache the result. Subsequent threads still pass through the gate, but the SDK
292+ * is expected to serve successful follow-up fetches from its own cache/fast path.
289293 *
290294 * @param url the URL to fetch the token for
291295 * @return the token fetch result (from cache or fresh SDK call)
@@ -297,7 +301,7 @@ static Approov.TokenFetchResult fetchApproovTokenWithGate(String url) {
297301 return cached ;
298302 }
299303
300- // 2. Slow path — gate ensures only one thread calls the SDK
304+ // 2. Slow path — gate ensures only one thread refreshes the failure state
301305 synchronized (fetchGateLock ) {
302306 // Double-check: another thread may have populated the cache while we waited
303307 cached = getCachedFailure ();
@@ -310,7 +314,7 @@ static Approov.TokenFetchResult fetchApproovTokenWithGate(String url) {
310314 Log .d (TAG , "gate: fetching token for " + url );
311315 Approov .TokenFetchResult result = Approov .fetchApproovTokenAndWait (url );
312316
313- // Cache only failures; success tokens are unique per-request
317+ // Cache only failures here ; success caching is handled inside the SDK.
314318 cacheFailureIfNeeded (result );
315319 return result ;
316320 }
@@ -1203,7 +1207,7 @@ public Response intercept(Chain chain) throws IOException {
12031207
12041208 // Fetch token using double-checked locking on the failure cache.
12051209 // Fast path: cached failure returned immediately (no lock).
1206- // Slow path: gate ensures only one thread calls the SDK ; others wait and re-check.
1210+ // Slow path: gate ensures only one thread refreshes failure state ; others wait and re-check.
12071211 Approov .TokenFetchResult approovResults = ApproovService .fetchApproovTokenWithGate (url .toString ());
12081212
12091213 // provide information about the obtained token or error (note "approov token -check" can
0 commit comments