GraphQL caching `ttlPerSchemaCoordinate`

I have a cell with this query

query StoreProductQuery($sku: String!, $lang: String) {
  categories(lang: $lang) {
    id
    name
    parent
  }
  product(sku: $sku, lang: $lang) {
    sku
    name
    short_desc
    long_desc
    regular_price
    unavailable
    images
  }
}

And I have this cache config

{
  ttl: 0,
  ttlPerSchemaCoordinate: {
    'Query.allProducts': ONE_HOUR,
    'Query.featuredProducts': ONE_DAY,
    'Query.topSellers': ONE_DAY,
    'Query.rootProducts': ONE_DAY,
    'Query.categories': ONE_DAY,
  },
}

With this setup I thought the categories part of my query would get cached for one day, but that the product part would never be cached. What I’m seeing though is that the whole query is cached for a full day. Is this the expected behavior? If so, how can I make it work like I thought it would?

Reading the ResponseCache docs

I found this example

ttlPerSchemaCoordinate: {
  // cache operation containing Query.rocketCoordinates selection for 100ms
  'Query.rocketCoordinates': 100,
},

And going by the comment there is seems like as long as a query contains one of the configured query names the full query will be cached. So, in my case, because my query contains categories the whole thing is cached for a day. Which is a bit of a bummer, because individual products are much more likely to be updated (price change etc) than a full category is added/edited/removed.

So I guess this is the expected behavior. Question still remains though how to work around it.


EDIT: Progress :slightly_smiling_face:

{
  ttl: 0,
  ttlPerSchemaCoordinate: {
    'Query.allProducts': ONE_HOUR,
    'Query.featuredProducts': ONE_DAY,
    'Query.topSellers': ONE_DAY,
    'Query.rootProducts': ONE_DAY,
    'Query.categories': ONE_DAY,
    'Query.product': 0,
  },
}

Force-disabling cache for product seems to stop caching. I’m afraid though that with that I also disable caching of the categories part of the query. But I don’t know.

@Tobbe You may want to ask this question in the envelop GitHub repo: Issues · dotansimha/envelop · GitHub

Also, have you tried to cache category and product at the ttlPerType level, and keep the others at schema level?

{
  ttl: 0,
  ttlPerType: {
    Category:  ONE_DAY,
    Product: 0,
  },
  ttlPerSchemaCoordinate: {
    'Query.allProducts': ONE_HOUR,
    'Query.featuredProducts': ONE_DAY,
    'Query.topSellers': ONE_DAY,
    'Query.rootProducts': ONE_DAY
  },
}

The thing is, remember this is a “Response” cache – it caches the entire document that is returned.

So, if the response has category and product data in it – and one item in that large document changes – then that entire document is purged/invalidated when any product or any category in that doc changes.

1 Like

I can confirm that this does disable caching of the categories part of my query as well. Not what I wanted.

{
  ttl: 0,
  ttlPerType: {
    Category:  ONE_DAY,
    Product: 0,
  },
  ttlPerSchemaCoordinate: {
    'Query.allProducts': ONE_HOUR,
    'Query.featuredProducts': ONE_DAY,
    'Query.topSellers': ONE_DAY,
    'Query.rootProducts': ONE_DAY
  },
}

@dthyresson’s suggestion from above goes the other way. It caches both categories and products for a full day

I added a question to the envelop repo [response-cache] Caching for multi-root queries · Discussion #1370 · dotansimha/envelop · GitHub

1 Like

Keep in mind that what is caches is the data response.

The rules state for how long to cache and what to invalidate.

Because you have two models’ data in the same response if the shorter of the two gets an invalidate then the entire cached response is purged — there is no partial response invalidation.

That makes sense. Thanks for pointing it out (again) :slight_smile:

Now, if there was an easier way to run more than one query in a cell… Hmm… Something to think about for v2?

1 Like

Caching is hard. :grinning:

1 Like