mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
docs: improve some basic docs on caching
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8887 Co-authored-by: Rob Dominguez <24390149+robertjdominguez@users.noreply.github.com> GitOrigin-RevId: 0597ca635eaf370053f0158925c6a531cc643311
This commit is contained in:
parent
30fbdf2e83
commit
37384ec60d
@ -5,7 +5,7 @@ keywords:
|
|||||||
- queries
|
- queries
|
||||||
- query
|
- query
|
||||||
- config
|
- config
|
||||||
sidebar_position: 3
|
sidebar_position: 4
|
||||||
---
|
---
|
||||||
|
|
||||||
import ProductBadge from '@site/src/components/ProductBadge';
|
import ProductBadge from '@site/src/components/ProductBadge';
|
||||||
@ -23,6 +23,9 @@ Schemas.
|
|||||||
Cached responses are stored for a period of time in a LRU (least-recently used) cache, and removed from the cache as per
|
Cached responses are stored for a period of time in a LRU (least-recently used) cache, and removed from the cache as per
|
||||||
a user-specified TTL (time-to-live) which defaults to 60 seconds.
|
a user-specified TTL (time-to-live) which defaults to 60 seconds.
|
||||||
|
|
||||||
|
For self-hosted Enterprise Edition, refer to the [enable caching](/enterprise/caching.mdx) documentation configure
|
||||||
|
various parameters.
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
In order to cache a query response, or to return an existing response from the cache (if one exists), simply add the
|
In order to cache a query response, or to return an existing response from the cache (if one exists), simply add the
|
||||||
@ -40,14 +43,6 @@ query MyCachedQuery @cached {
|
|||||||
If the response was cached successfully, the HTTP response will include a `Cache-Control` header, whose value
|
If the response was cached successfully, the HTTP response will include a `Cache-Control` header, whose value
|
||||||
(`max-age={SECONDS}`) indicates the maximum number of seconds for the returned response to remain in the cache.
|
(`max-age={SECONDS}`) indicates the maximum number of seconds for the returned response to remain in the cache.
|
||||||
|
|
||||||
A query's response can be cached only if the following conditions hold:
|
|
||||||
|
|
||||||
- For queries using `Actions` or `Remote Schemas`, the query does **not** make use of `forward_client_headers` (see
|
|
||||||
[RemoteSchemaDef](/api-reference/syntax-defs.mdx#remoteschemadef) and
|
|
||||||
[ActionDefinition](/api-reference/syntax-defs.mdx#actiondefinition)).
|
|
||||||
- The response JSON is **under** 100KB in size
|
|
||||||
|
|
||||||
For self-hosted Enterprise Edition, refer to the [enable caching](/enterprise/caching.mdx) documentation.
|
|
||||||
|
|
||||||
## Controlling cache lifetime
|
## Controlling cache lifetime
|
||||||
|
|
||||||
@ -89,29 +84,6 @@ different query and will generate a new cache key.
|
|||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Rate Limiting
|
|
||||||
|
|
||||||
Cache writes are rate limited, with a rate depending on your plan. The rate limit is based on the total number of bytes
|
|
||||||
written to the cache in a sliding window. If you exceed the rate limit, the HTTP response will indicate this with a
|
|
||||||
warning header:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
Warning: 199 - cache-store-capacity-exceeded
|
|
||||||
```
|
|
||||||
|
|
||||||
:::info Sliding window policies
|
|
||||||
|
|
||||||
A sliding window policy maintains a queue of a specified size, into which entities flow. When the queue is full and a
|
|
||||||
new entity arrives, the oldest entity in the queue is removed from the window (FIFO).
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Session variables
|
|
||||||
|
|
||||||
A session variable will only influence the cache key for a query if it is referenced by the execution plan. In practice,
|
|
||||||
this means that session variables are only factored into cache keys if they are referenced in the permissions for a
|
|
||||||
query. See the [API permissions](/api-reference/metadata-api/permission.mdx) documentation for more information.
|
|
||||||
|
|
||||||
## Response headers
|
## Response headers
|
||||||
|
|
||||||
When you enable caching for a query, the following headers should be returned in the HTTP response:
|
When you enable caching for a query, the following headers should be returned in the HTTP response:
|
||||||
|
193
docs/docs/caching/how-it-works.mdx
Normal file
193
docs/docs/caching/how-it-works.mdx
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
---
|
||||||
|
description: How caching works
|
||||||
|
title: How it works
|
||||||
|
keywords:
|
||||||
|
- caching
|
||||||
|
- queries
|
||||||
|
- query
|
||||||
|
- how-to
|
||||||
|
sidebar_position: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
## What is cached exactly?
|
||||||
|
|
||||||
|
Hasura Caching is a type of response caching that helps you cache results of a given query. Hasura will cache the
|
||||||
|
response of a given "unique" query, and only if the same query is made again (i.e., has the same cache key) will it hit
|
||||||
|
the cache. We explain how the cache key is computed in the [next section](#how-is-the-cache-key-computed).
|
||||||
|
|
||||||
|
This means that there is no sharing of the cache if:
|
||||||
|
|
||||||
|
- the session variables differ, even if the GraphQL query, variables, operation name everything is the same
|
||||||
|
- the GraphQL variables differ, even if the GraphQL query is the same
|
||||||
|
- the operation name is different, even if the GraphQL query is the same
|
||||||
|
- the GraphQL query differs only in one or a few fields
|
||||||
|
|
||||||
|
## How is the cache key computed?
|
||||||
|
|
||||||
|
If the `@cached` directive is used in a GraphQL operation, Hasura computes a cache key. This is then used to look up and
|
||||||
|
store values in the cache.
|
||||||
|
|
||||||
|
The cache key is a hash of:
|
||||||
|
|
||||||
|
- the GraphQL query
|
||||||
|
- the GraphQL operation name
|
||||||
|
- the GraphQL variables of the query
|
||||||
|
- the [role and session variables](/auth/authorization/roles-variables.mdx) used in permissions of the query
|
||||||
|
- request headers in case of [Remote Schemas](/remote-schemas/overview.mdx) or [Actions](/actions/overview.mdx) when
|
||||||
|
`forward_client_headers` is `true`
|
||||||
|
|
||||||
|
If the computed cache key is found in the cache, then there is a cache hit.
|
||||||
|
|
||||||
|
:::info TTL matters
|
||||||
|
|
||||||
|
Note that the cache hit also depends on the TTL and not just cache key. See [below](#cache-invalidation) to know more
|
||||||
|
about cache TTL.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
### GraphQL query
|
||||||
|
|
||||||
|
This includes the entire GraphQL query text. Any difference in the GraphQL query text is considered a different query.
|
||||||
|
**Only whitespace is ignored.**
|
||||||
|
|
||||||
|
For example, all the following queries are considered **different**:
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query MyCachedQuery @cached {
|
||||||
|
users {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query MyCachedQuery @cached {
|
||||||
|
users {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query MyCachedQuery @cached {
|
||||||
|
users {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
created_at
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the order of objects inside an input argument are changed, even then it is considered a **different** query:
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query MyCachedQuery @cached {
|
||||||
|
profile(where: { _and: [{ id: { _gt: 1 } }, { name: { _ilike: "%x%" } }] }) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query MyCachedQuery @cached {
|
||||||
|
profile(where: { _and: [{ name: { _ilike: "%x%" } }, { id: { _gt: 1 } }] }) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Only whitespace is ignored, so the following queries are considered the **same**:
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query MyCachedQuery @cached {
|
||||||
|
users {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query MyCachedQuery @cached {
|
||||||
|
users { name id }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Operation name
|
||||||
|
|
||||||
|
In the following example, the operation name is `MyCachedQuery`
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query MyCachedQuery @cached {
|
||||||
|
users {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If we use the same name, but change the query, then it is considered a **different** query:
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query MyCachedQuery @cached {
|
||||||
|
users {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GraphQL variables
|
||||||
|
|
||||||
|
The following example shows variables declared and used called `minDate` and `maxDate`. Usually, when executing the
|
||||||
|
operation, one would pass the actual value of these variables.
|
||||||
|
|
||||||
|
If these variable **values** differs across queries, then they are deemed **different**:
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query getNewlyJoinedUsers($minDate: timestamptz!, $maxDate: timestamptz!) @cached {
|
||||||
|
users(where: { _and: [{ created_at: { _gt: $minDate } }, { created_at: { _lt: $maxDate } }] }) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Role and session variables
|
||||||
|
|
||||||
|
Hasura resolves [session variables](/auth/authorization/roles-variables.mdx) via the
|
||||||
|
[authentication](/auth/authentication/index.mdx) process. The role and session variables are used to compute the cache
|
||||||
|
key.
|
||||||
|
|
||||||
|
A session variable will only influence the cache key for a query if it is referenced by the execution plan. In practice,
|
||||||
|
this means that session variables are only factored into cache keys if they are referenced in the permissions for a
|
||||||
|
query.
|
||||||
|
|
||||||
|
For example, if a JWT resolves to say `x-hasura-user-id` and `x-hasura-org-id` session variables, but the query only
|
||||||
|
uses the `x-hasura-user-id` in the permissions, then only the role and `x-hasura-user-id` would be used to compute the
|
||||||
|
cache key.
|
||||||
|
|
||||||
|
### Request headers
|
||||||
|
Request headers (ignoring `x-request-id` header) are added to the cache key computation, when executing Remote Schema
|
||||||
|
or Action queries, if they have `forward_client_headers` set to `true`.
|
||||||
|
|
||||||
|
## Cache Invalidation
|
||||||
|
|
||||||
|
Cache invalidation in Hasura is based on TTLs. Hasura doesn't support any other "automatic" way to invalidate cache
|
||||||
|
(like on specific mutations). However, there are
|
||||||
|
[API endpoints](/docs/caching/caching-config.mdx#clearing-items-from-the-cache) to clear the cache manually.
|
||||||
|
|
||||||
|
The default TTL is 60 seconds. This can be increased via the
|
||||||
|
[TTL argument](/caching/caching-config.mdx/#controlling-cache-lifetime) in the cached directive.
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
Cache writes are rate limited, with a rate depending on your plan. The rate limit is based on a leaky bucket algorithm.
|
||||||
|
If you exceed the rate limit, the HTTP response will indicate this with a warning header:
|
||||||
|
|
||||||
|
```http
|
||||||
|
Warning: 199 - cache-store-capacity-exceeded
|
||||||
|
```
|
Loading…
Reference in New Issue
Block a user