Code

Opened 4 years ago

Closed 2 years ago

#13894 closed Bug (wontfix)

Disable upstream caching with messages framework

Reported by: bronger Owned by: nobody
Component: contrib.messages Version: 1.2
Severity: Normal Keywords:
Cc: bronger@… Triage Stage: Design decision needed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Upstream caching should be disabled when messages have been consumed in the current request. I added

    if request._messages.used:
        add_never_cache_headers(response)

to "process_response" of MessageMiddleware and it works nicely for me. Doesn't it make sense to do that always, or at least, by default?

Rationale:

When the message framework is used and the messages are iterared over in the current view, this means that it is posible that they are displayed and consumed. Thus, when the same page is retrieved next time, they won't appear, or with different content.

It is very difficult to handle this in cache-related code of that view because the messages have been generated in a previous request, which may even belong to another view.

Attachments (0)

Change History (5)

comment:1 Changed 4 years ago by SmileyChris

  • Component changed from Uncategorized to Contrib apps
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Design decision needed

It does sound like a valid issue.

But isn't the opposite true as well? If a page (without any messages displayed) is cached, then assuming messages were in the queue and this page was hit again, the messages will not get rendered (or consumed). It seems like fixing this only fixes half of the caching problem.

comment:2 Changed 4 years ago by bronger

First of all: As we had to find out, "add_never_cache_headers" doesn't work. It only sets "Expires" and "Cache-control/max-age" but it also sets "ETag" and "Last-Modified" so that the next request may be taken from the browser's cache. (It's strange that such a function is called "add_never_cache_headers". It should be called "add_expire_immediately_headers". Anyway.)

Instead, we use

if request._messages.used:
    del response["ETag"]
    del response["Last-Modified"]
    response["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
    # FixMe: One should check whether the following settings are
    # sensible.
    response["Pragma"] = "no-cache"
    response["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate, private"

Now to your question. You're absolutely right. We don't run into this problem because messages are shown on pages which have recently changed anyway (the message reads "You have successfully changed ..."). If we had a message saying "Editing aborted. Nothing was changed.", it would not get displayed.

comment:3 Changed 3 years ago by gabrielhurley

  • Component changed from Contrib apps to contrib.messages

comment:4 Changed 3 years ago by graham_king

  • Severity set to Normal
  • Type set to Bug

comment:5 Changed 2 years ago by aaugustin

  • Easy pickings unset
  • Resolution set to wontfix
  • Status changed from new to closed
  • UI/UX unset

I don't think Django can handle this problem automatically and correctly.

It is a very common pattern to loop over messages in the base template of a website. If we disable caching simply because messages might be displayed on a given page, we're just killing the cache for most websites. If we disable it only when messages are displayed, we're only resolving half of the problem, as explained in comments 1 and 2.

To sum up:

  • Caching dynamic pages is hard :)
  • Use ETags to save bandwidth — Django provides a lot of flexibility at this level.
  • Use fragment caching in templates to save CPU — but don't cache dynamic parts, like messages!

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.