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

Adds dynamic query cache-control #4540

Merged
merged 72 commits into from Jan 19, 2023
Merged

Adds dynamic query cache-control #4540

merged 72 commits into from Jan 19, 2023

Conversation

tobias-tengler
Copy link
Collaborator

@tobias-tengler tobias-tengler commented Dec 12, 2021

Allow to annotate the GraphQL schema with caching hints and add middleware that dynamically computes the cache expiration time on a per query basis. In this first iteration these cache hints are used to set the HTTP Cache-Control header, but I've also did some preparation work for custom user-space cache implementation for example using Redis. However there were some open questions around short-circuiting and cache key computation that were stalling the original PR, so I decided to leave them out.

Closes #2089

Examples

The examples below only show how to apply the @cacheControl directive on object type fields, but the directive can also be applied on object types, interfaces and union types. If a field returns a type that specifies a @cacheControl directive, the field will use the cache information from the type, unless the field itself specifies a @cacheControl directive.

Annotation-based

services.AddGraphQLServer()
    .AddHttpQueryCache()
    .UseQueryCachePipeline()
    .ModifyCacheControlOptions(options =>
    {
        options.Enable = true;
        options.ApplyDefaults = true;
        options.DefaultMaxAge = 0;
    })
    .AddQueryType<Query>();

public class Query
{
    [CacheControl(100, Scope = CacheControlScope.Private)]
    public string Foo() => "Bar";
}

Code-first

services.AddGraphQLServer()
    .AddHttpQueryCache()
    .UseQueryCachePipeline()
    .ModifyCacheControlOptions(options =>
    {
        options.Enable = true;
        options.ApplyDefaults = true;
        options.DefaultMaxAge = 0;
    })
    .AddQueryType<QueryType>();

public class QueryType : ObjectType
{
    protected override void Configure(IObjectTypeDescriptor descriptor)
    {
        descriptor.Field("foo")
            .Resolve("bar")
            .CacheControl(100, scope: CacheControlScope.Private);
    }
}

Schema-first

services.AddGraphQLServer()
    .AddHttpQueryCache()
    .UseQueryCachePipeline()
    .ModifyCacheControlOptions(options =>
    {
        options.Enable = true;
        options.ApplyDefaults = true;
        options.DefaultMaxAge = 0;
    })
    .AddDocumentFromString(@"
        type Query {
            foo: String @cacheControl(maxAge: 100 scope: PRIVATE)
        }
    ");

@michaelstaib
Copy link
Member

michaelstaib commented Dec 12, 2021

Awesome Tobias, will go through it tonight

@sonarcloud
Copy link

sonarcloud bot commented Dec 12, 2021

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@sonarcloud
Copy link

sonarcloud bot commented Feb 23, 2022

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@stale stale bot added the ⌛ stale Nothing happened with this issue in quite a while label May 4, 2022
@stale stale bot closed this May 11, 2022
@zf-jsk
Copy link

zf-jsk commented May 16, 2022

@tobias-tengler Thanks. with this branch, can we try cacheControl directive. It would be great, if any usage snippets added here.
Also is this targeted with v13, kindly confirm. thanks.

@imranmomin
Copy link

@tobias-tengler @michaelstaib Thank you. It would be great if this can be targeted to v13

@tobias-tengler
Copy link
Collaborator Author

@zf-jsk You can try out the HTTP query cache by registering it like this:

services.AddGraphQLServer()
    .AddHttpQueryCache()
    .UseQueryCachePipeline()
    // optional:
    .ModifyCacheControlOptions(options => { })

You can then use the CacheControl() method in Code-first, the [CacheControl] attribute in Annotation-based or the @cacheControl directive in Schema-first to specify rules.

I haven't worked on this in a while, so I'm no longer sure what the current limitations are, but if I remember correctly it should cover basic use cases.

If custom caches are not part of the first iteration then I think this could go into v13. I'll try to spend some time on it to get it usable with HTTP Cache-Control. :)

@stale stale bot removed the ⌛ stale Nothing happened with this issue in quite a while label May 19, 2022
@michaelstaib michaelstaib removed the 👓 ready-for-review The PR is ready for review. label Jan 19, 2023
@michaelstaib michaelstaib merged commit 9fb5268 into main Jan 19, 2023
@michaelstaib michaelstaib deleted the tte/cache-control branch January 19, 2023 21:25
@ChilliCream ChilliCream deleted a comment from stale bot Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Proposal for dynamic query cache control
7 participants