Ryan Aquino
Ryan Aquino

Reputation: 150

Django REST framework still respond with cached data even after having empty redis keys

Context: I am facing an issue when caching through redis ModelViewSet API view in Django REST framework (DRF) using method decorator cache_page.

Docs reference: https://www.django-rest-framework.org/api-guide/caching/

Code Snippet: https://hastebin.com/apoqeloyav.py

Example Scenario

Here is the current behavior (tested manually using Swagger UI)

  1. send GET request to /products endpoint -> this will request to my DRF server and cache the view

  2. send GET request to /products endpoint again -> this will respond products data as cached data (as verified in dev tools network tab "Served from disk cache"). It also means that it didn't hit my DRF server to retrieve the data.

  3. send PATCH request to /products/{product_id} endpoint -> this will update details then invalidate cache (Redis cache keys are now empty at this point)

  4. send GET request to /products endpoint again -> This will still respond product data as cached data (verified because the updated data from doing step 3 is still not present). It also means that it didn't hit my DRF server to retrieve the data.

enter image description here

Here is my expected behavior (tested manually using Swagger UI)

  1. send GET request to /products endpoint -> this will request to my DRF server and cache the view
  2. send GET request to /products endpoint again -> this will respond products data as cached data (as verified in dev tools network tab "Served from disk cache"). It also means that it didn't hit my DRF server to retrieve the data.
  3. send PATCH request to /products/{product_id} endpoint -> this will update details then invalidate cache (Redis cache keys are now empty at this point)
  4. send GET request to /products endpoint again -> This should respond product data that comes from the database. This means it hits my DRF server to retrieve the updated data.

How do I get the expected results so that if redis cache is empty, it should hit my DRF server to retrieve the latest data and cache the succeeding calls until its invalidated again? Also, I am not sure if this is an issue, or just a normal behavior.

Here is what I tried so far when invalidating the cached data from redis, but none of them works and still serves cached data

  1. set cache expiry to 0
  2. set cache value to None
  3. Delete all keys programmatically
  4. Delete all keys via redis-cli
  5. Shutdown redis-server -> but still serves from disk cache and does not hit my DRF API endpoint

Here are the version sI am using

Upvotes: 1

Views: 2876

Answers (1)

Igor Moraru
Igor Moraru

Reputation: 7729

The request from 4. does not even hit the redis cache, because it returns a local cache (note the "From disk cache" in response code).

You should differentiate between a public cache (i.e. the server cache used by all users) and a private cache (the user's browser cache).

I think, when using cache_page decorator, other than caching the request, it also sets "Cache-control" response headers to allow a private cache of the request. The browser uses those headers to cache the request locally, and return a local cached response until max-age expires.

To prevent this behaviour, at the server level, you can use @never_cache decorator, which sets Cache-control response headers to prevent local caching, or use @cache_control(public=True) to allow only public cache of the request (this also tweaks the cache control response headers accordingly).

More on Controlling cache.

Upvotes: 2

Related Questions