[Django] Cache aufräumen...

Django, Flask, Bottle, WSGI, CGI…
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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"

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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 :(

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

Willst du mal ein Beispiel zu deiner Verwendung des caching systems geben? Werde aus deiner Problemstellung gerade nicht wirklich schlau.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

Warum splittest du die URL dann nicht einfach? Ein Artikel soll ja für alle User gleich aussehen unabhängig von session_id etc.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Nein. Die Seite sieht eigentlich identisch aus. Bis auf den CSRF token.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

Du kannst doch sicherlich nen eigenen Cache decorator schreiben der auf den Token verzichtet…
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

Lass halt den Breich in dem der Token ist raus, das ist ja das einzig variable an der Seite...
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

Eigene Middleware implementieren, die den Token noch im Nachhinein in den gecacheten Wert reinschreibt?
Antworten