ravendb icon indicating copy to clipboard operation
ravendb copied to clipboard

Outdated data when using AggressivelyCache

Open elitastic opened this issue 1 year ago • 2 comments

If a certain combination of Query<T> and AggressivelyCache is used, outdated data is loaded. Could you please check the following failing test? Is this correct behaviour?

Notice: If ‘AggressivelyCache’ is commented out, the test passes..

Tested with latest Raven 5 (5.4.202) and Raven 6 (6.2.0) versions.

public class AggressivelyCacheFails : RavenTestDriver
{
    [Fact]
    public void AggressivelyCache()
    {
        using var store = GetDocumentStore();

        using (var session = store.OpenSession())
        {
            session.Store(new TestDocument { Name = "Peter" });
            session.SaveChanges();
        }

        WaitForIndexing(store);

        using (var session = store.OpenSession())
        {
            var documents = session.Query<TestDocument>().ToList();

            documents.First().Name = "Joe";

            session.SaveChanges();
        }

        WaitForIndexing(store);

        using (var session = store.OpenSession())
        {
            using (session.Advanced.DocumentStore.AggressivelyCache()) // If this line is commented out, the test passes..
            {
                var documents = session.Query<TestDocument>().ToList();

                Assert.Single(documents, d => d.Name == "Joe");
            }
        }
    }

    private class TestDocument
    {
        public string Name { get; set; }
    }
}

elitastic avatar Sep 27 '24 09:09 elitastic

AggressivelyCache is there for a reason - it is a way to mark that there is latency involved in refreshing the cache. If you add a 500 ms delay, does this still fail for you?

If not, then this is by design, since there is a race here between the server updating the data / index and updating the client that there have been changes.

ayende avatar Sep 27 '24 09:09 ayende

A delay does not help. Adding "Customize(c => c.NoCaching())" does help.

public class AggressivelyCacheFails : RavenTestDriver
{
    [Fact]
    public void AggressivelyCache()
    {
        using var store = GetDocumentStore();

        using (var session = store.OpenSession())
        {
            session.Store(new TestDocument { Name = "Peter" });
            session.SaveChanges();
        }

        WaitForIndexing(store);

        using (var session = store.OpenSession())
        {
            var documents = session
                .Query<TestDocument>()
                .Customize(c => c.NoCaching())  // this does help
                .ToList();

            documents.First().Name = "Joe";

            session.SaveChanges();
        }

        WaitForIndexing(store);

        using (var session = store.OpenSession())
        {
            using (session.Advanced.DocumentStore.AggressivelyCache()) // If this line is commented out, the test passes..
            {
                var documents = session.Query<TestDocument>().ToList();

                Assert.Single(documents, d => d.Name == "Joe");
            }
        }
    }

    private class TestDocument
    {
        public string Name { get; set; }
    }
}

elitastic avatar Sep 27 '24 09:09 elitastic

As a delay does not change the behaviour, should this be investigated further?

elitastic avatar Oct 22 '24 07:10 elitastic

hi @elitastic

I've just tested your code on net462, netcoreapp3.1, net5.0, net6.0, net7.0 and net8.0 and it passes in all of those targets. Is there a chance that you can prepare a sample csproj project that reproduces your issue?

Also what OS do you have? Maybe it is significant here.

ppekrol avatar Oct 22 '24 08:10 ppekrol

Hi @ppekrol

I'm on Win 11 and .net 8.0, have you tested with the original code of the first post (without .Customize(c => c.NoCaching()))?

elitastic avatar Oct 22 '24 09:10 elitastic

Ok, my bad. Reproduced. I will deep dive into that and check what is going on, thanks.

ppekrol avatar Oct 22 '24 11:10 ppekrol

I've looked into this and it looks like follows:

  • Regular and Aggressive cache are using same cache entry, Aggressive cache is just checking if that entry meets it's requirements and uses it (no request sent) or discards it (and sends the request). This means that regular, not aggressively cached, request will impact the cache and results that are returned by the aggressively cached one (policy is: 'if we know that there is a newer data there - let's use it').
  • Aggressive cache by default works in TrackChanges mode, but tracking is only done from the first ever call to Aggressive cache, so in case of your test, aggressive cache starts tracking at the very end, so it is completely unaware of the change made before that

To enable tracking in your case, you can do as follows:

using var store = GetDocumentStore();

using (store.AggressivelyCache()) // this will enable tracking
{
}

using (var session = store.OpenSession())
...

This will enable tracking from the very beginning. Of course please have in mind that tracking is 'racy', it is an event sent by server to the Client API to clear the cached value, s it would be advisable to wait 'a bit' before doing last, aggressively cached, query.

ppekrol avatar Oct 23 '24 13:10 ppekrol

OK, many thanks for your explanations.

elitastic avatar Nov 06 '24 13:11 elitastic