Coder Social home page Coder Social logo

Comments (12)

aschepp avatar aschepp commented on September 28, 2024 1

Yeah, we normally use Awaitility, but it wasn't important in this case. I will test it next week, when I am working on this again and let you know. I'm pretty sure I already tested it with an executor as well. I just removed it to keep the test as small as possible.

from caffeine.

ben-manes avatar ben-manes commented on September 28, 2024

Thanks! Can you check if this is the same as #1478? Sorry, I haven't had time to work on this project and will try to trace through your test this evening.

from caffeine.

ben-manes avatar ben-manes commented on September 28, 2024

Oh, that other issue was only for an AsyncCache and unrelated to this.

Here your tests passes for me and I see multiple refreshes. If I add a println to your loader then it shows two refreshes. So it seems to be working on v3.1.8. What version are you using?

from caffeine.

aschepp avatar aschepp commented on September 28, 2024

Sorry, I should have written the test, so that it fails. In the correct case, all the times(x) should increase, but it doesn't in the second one.

from caffeine.

aschepp avatar aschepp commented on September 28, 2024

It should fail like this.

@Test
public void refreshingCacheWithRuntimeException() throws InterruptedException {
	RuntimeExceptionTestCacheLoader runtimeExceptionTestCacheLoader = Mockito.spy(new RuntimeExceptionTestCacheLoader());
	LoadingCache<String, String> cache = Caffeine.newBuilder()
		.refreshAfterWrite(Duration.ofNanos(1))
		.expireAfterWrite(Duration.ofSeconds(1))
		.build(runtimeExceptionTestCacheLoader::apply);

	cache.put("key", "value");
	String value = cache.get("key");
	assertEquals("value", value);
	verify(runtimeExceptionTestCacheLoader, timeout(1000).times(1)).apply("key");
	value = cache.get("key");
	assertEquals("value", value);
	// This should've already called the loader again, but it doesn't.
	verify(runtimeExceptionTestCacheLoader, timeout(1000).times(2)).apply("key");
	// Wait for it to expire
	Thread.sleep(1500);
	assertThrows(RuntimeException.class, () -> cache.get("key"));
	verify(runtimeExceptionTestCacheLoader, timeout(2000).times(3)).apply("key");
}

public static class RuntimeExceptionTestCacheLoader implements Function<String, String> {

	@Override
	public String apply(String key) {
		throw new RuntimeException("Test");
	}
}

from caffeine.

ben-manes avatar ben-manes commented on September 28, 2024

I think you might be hitting a race condition because you are using the default executor, making things async. If I use a caller runs executor and make it more explicit using a CacheLoader, then I think it gives the right results?

  @Test
  public void refreshingCacheWithRuntimeException() throws InterruptedException {
    var runtimeExceptionTestCacheLoader = Mockito.spy(new RuntimeExceptionTestCacheLoader());
    LoadingCache<String, String> cache = Caffeine.newBuilder()
        .executor(Runnable::run)
        .refreshAfterWrite(Duration.ofNanos(1))
        .expireAfterWrite(Duration.ofSeconds(1))
        .build(runtimeExceptionTestCacheLoader);

    cache.put("key", "value");
    String value = cache.get("key");
    assertEquals("value", value);
    verify(runtimeExceptionTestCacheLoader, timeout(1000).times(1)).reload(eq("key"), anyString());
    value = cache.get("key");
    assertEquals("value", value);
    // This should've already called the loader again, but it doesn't.
    verify(runtimeExceptionTestCacheLoader, timeout(1000).times(2)).reload(eq("key"), anyString());
    // Wait for it to expire
    Thread.sleep(1500);
    assertThrows(RuntimeException.class, () -> cache.get("key"));
    verify(runtimeExceptionTestCacheLoader, timeout(2000).times(1)).load("key");
  }

  public static class RuntimeExceptionTestCacheLoader implements CacheLoader<String, String> {
    @Override
    public String load(String key) {
      System.err.println("Loading key: " + key);
      throw new RuntimeException("Test");
    }
    @Override
    public String reload(String key, String oldValue) {
      System.err.println("Refreshing key: " + key);
      throw new RuntimeException("Test");
    }
  }

from caffeine.

ben-manes avatar ben-manes commented on September 28, 2024

fyi adding .executor(Runnable::run) to your test passes

from caffeine.

ben-manes avatar ben-manes commented on September 28, 2024

When you do want to write a concurrent test, using a FakeTicker and Awaitility to manage time and concurrency really helpful. Using sleeps is unfortunately error prone so its better to coordinate it more explicitly. Those two are really good tools.

from caffeine.

aschepp avatar aschepp commented on September 28, 2024

Actually, I tested it really quick, yes adding an executor seems to fix it. What I did was adding a scheduler in the past.

from caffeine.

aschepp avatar aschepp commented on September 28, 2024

Thanks for your help! Really appreciate it.

from caffeine.

ben-manes avatar ben-manes commented on September 28, 2024

thanks. When I sprinkle some awaits after the cache.get calls then it passes using the default executor,

await().until(() -> cache.policy().refreshes().isEmpty());

from caffeine.

ben-manes avatar ben-manes commented on September 28, 2024

wonderful! glad its not an issue. let me know if you run into anything else.

from caffeine.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.