Seite 1 von 1

[Django] Cache aufräumen...

Verfasst: Montag 26. April 2010, 15:12
von jens
Ich nutzte das Cache system von Django mit UpdateCacheMiddleware und FetchFromCacheMiddleware.

Das Problem: Wie kann man veraltete Einträge aus dem Cache löschen?

Leider gibt es kein "Lösche gesamten Cache". Also kann man nur gezielt Einträge aus dem Cache entfernen. Das klappt solange man den cache_key heraus bekommt. Ich nutzte dazu django.utils.cache._generate_cache_key

Wenn man allerdings z.B. auf einer Seite die Django comments nutzt, wir response Vary auf "Cookie" gesetzt. Alle Vary Angaben werden in den cache key einbezogen. Somit kann man den cache key nicht mehr erhalten.

Wenn also bsp. ein Blog Eintrag geändert wird, sieht ein Client die Änderungen erst, wenn der Cache Eintrag Abgelaufen ist :(

Was also tun?
1. Zu dem cache Backend eine "lösch alle Einträge" selber implementieren?
2. Eigene Cache middleware implementieren, die niemals cached, wenn ein vary header gesetzt ist?
3. Alle gültigen session cookies durchgehen und cache_key damit bilden

Keine wirklich guten Lösungen.

EDIT: Interessant in dem Zusammenhang: "LocaleMiddleware breaks caching. (Vary: Cookie)": http://code.djangoproject.com/ticket/13217 steht allerdings auf "closed: wontfix"

Verfasst: Montag 26. April 2010, 16:29
von jens
Hab festgestellt, das nicht nur die sessionid in den cache_key einfließt, sondern auch der CSRF token.

Somit ist es im Grunde unmöglich gezielt eine Seite aus dem Cache zu löschen, wenn comments oder CSRF auf dieser genutzt wird :(

Verfasst: Montag 26. April 2010, 17:41
von nemomuk
Willst du mal ein Beispiel zu deiner Verwendung des caching systems geben? Werde aus deiner Problemstellung gerade nicht wirklich schlau.

Verfasst: Dienstag 27. April 2010, 07:14
von jens
Im Grunde ist es ein allgemeines Problem:

Ein view zeigt irgendein Datenbank Inhalt. Als Cache kommt UpdateCacheMiddleware und FetchFromCacheMiddleware zum Einsatz.
Wenn ich den Datenbank Inhalt editiere, möchte ich gern den Cache Eintrag löschen. (Ansonsten sieht der Client ja eine veraltete Seite)

Der Cache Key setzt sich normalerweise aus der URL zusammen. Hat man also die URL, kann man aus dieser den Cache Key generieren und den Cache Eintrag löschen.

So weit so gut...

Nutzt der view allerdings im Template eine Comments form, oder eine andere POST Form mit CSRF, dann hat man ein Problem. Denn der cache key setzt sich dann aus URL + session ID + CSRF token zusammen.
Ändert man den Datenbank Inhalt, kann man den cache key nicht mehr "nach" generieren und somit kann man den Cache Eintrag nicht mehr löschen.

Wenn CSRF genutzt wird, wird die Seite für jeden Client separat gecached und man kann diese Cache Einträge nicht mehr ohne weiteres löschen?
Ist das Fazit also: Die cache Zeitraum nicht ganz so hoch wählen? Oder cache timeout für Seiten die CSRF nutzten verringern?
Oder comments POST Form immer per AJAX nachladen?

Verfasst: Dienstag 27. April 2010, 07:41
von jens
Mir fällt da gerade eine bessere Möglichkeit ein:

Was braucht man? Man muß die möglichkeit haben, alle Cache Einträge nach der URL zu löschen, auch wenn via vary mehrere Cache Einträge erstellt wurden.

Die Lösung: Man merkt sich einfach die cache keys pro Seite und implementiert eine Lösch-Methode, die dann alle cache keys löscht.

EDIT: Ah, sehe gerade cache.clear() ist neu in Django! Damit kann man den gesammten cache löschen. Mach es nun so: http://github.com/jedie/PyLucid/commit/ ... 51ce5b6d94

Verfasst: Dienstag 27. April 2010, 13:49
von nemomuk
Warum splittest du die URL dann nicht einfach? Ein Artikel soll ja für alle User gleich aussehen unabhängig von session_id etc.

Verfasst: Dienstag 27. April 2010, 13:51
von jens
Nein. Die Seite sieht eigentlich identisch aus. Bis auf den CSRF token.

Verfasst: Dienstag 27. April 2010, 14:29
von apollo13
Du kannst doch sicherlich nen eigenen Cache decorator schreiben der auf den Token verzichtet…

Verfasst: Dienstag 27. April 2010, 15:37
von jens
Was heißt auf den Token verzichten?

Man kann den Token mit cachen, aber dann funktioniert das für die meisten User nicht mehr.
Oder man kann die Seite auslassen...

Verfasst: Dienstag 27. April 2010, 16:14
von nemomuk
Lass halt den Breich in dem der Token ist raus, das ist ja das einzig variable an der Seite...

Verfasst: Dienstag 27. April 2010, 18:41
von jens
Ja, ok. Aber wie implementieren? Ich kann dann nicht mehr mit UpdateCacheMiddleware und FetchFromCacheMiddleware arbeiten. Schließlich wird damit immer der komplette response gecached. Was ja auch fast immer funktioniert.

Verfasst: Dienstag 27. April 2010, 22:46
von nemomuk
Eigene Middleware implementieren, die den Token noch im Nachhinein in den gecacheten Wert reinschreibt?