Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception from weigher is ignored in an AsyncCache #1687

Open
chaoren opened this issue May 4, 2024 · 1 comment
Open

Exception from weigher is ignored in an AsyncCache #1687

chaoren opened this issue May 4, 2024 · 1 comment

Comments

@chaoren
Copy link

chaoren commented May 4, 2024

Here's a test case:

  @Test
  public void weigher() {
    AsyncCache<String, String> cache =
        Caffeine.newBuilder()
            .maximumWeight(0)
            .weigher(
                ((key, value) -> {
                  throw new RuntimeException();
                }))
            .buildAsync();

    // case 1
    assertThrows(
        RuntimeException.class,
        () -> cache.get("key", (key, executor) -> completedFuture("value"))); // pass
    assertThat(cache.asMap()).isEmpty(); // pass

    // case 2
    var future = cache.get("key", (key, executor) -> new CompletableFuture<>());
    assertThrows(RuntimeException.class, () -> future.complete("value")); // fail
    assertThat(cache.asMap()).isEmpty(); // fail
  }

The first case:

cache.get("key", (key, executor) -> completedFuture("value"))

throws as expected. The cache also remains empty after the exception.

The second case:

future.complete("value")

however, does not throw at all. Probably impossible to get it to throw due to how CompletableFutures are structured, but the exception doesn't seem to be logged anywhere either. It seems to be silently ignored. Also, the entry remains in the cache after the exception.

@ben-manes
Copy link
Owner

ben-manes commented May 4, 2024

It must be these lines below that need to handle if the replacement fails exceptionally. The future completed and the dependent action tries to update the metadata. In a synchronous cache the operation would fail untouched, as one would expect, but here we already stored it and need to unpin it (has a weight of zero while in-flight). It would need to log the exception try to conditionally remove it in that scenario, which would bubble up to the removal listener as the explicit cause (which I think guava/caffeine does elsewhere, like on a discarded refresh).

// update the weight and expiration timestamps
cache().statsCounter().recordLoadSuccess(loadTime);
cache().replace(key, castedFuture, castedFuture, /* shouldDiscardRefresh */ false);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants