Opened 6 years ago

Closed 6 years ago

#29183 closed Uncategorized (invalid)

"cache" template tag should not render empty strings on failure

Reported by: Nicolas Le Manchet Owned by: nobody
Component: Core (Cache system) Version: 2.0
Severity: Normal Keywords: cache, template, memcached, pylibmc
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

The cache template tag renders an empty string when a connection errors happens while fetching from the cache.

I believe that the "cache" template tag should try to fetch from the cache, but fall back to being a noop in case of error.

Example:

An included template contains an expensive calculation wrapped in a cache tag:

<div class="content">
    {% cache 600 cleaned_article article.id %}{{ article.content | clean_article | safe }}{% endcache %}
</div>

If any error happens while fetching from the cache, the included template is rendered as an empty string and the following warning is printed in logs:

[2018-03-03 17:36:08,140 WARNI waitress django.template] Exception raised while rendering {% include %} for template 'reader/home.html'. Empty string rendered instead.
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 194, in render
    return template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 177, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/test/utils.py", line 98, in instrumented_test_render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/defaulttags.py", line 211, in render
    nodelist.append(node.render_annotated(context))
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/templatetags/cache.py", line 45, in render
    value = fragment_cache.get(cache_key)
  File "/usr/local/lib/python3.6/site-packages/django/core/cache/backends/memcached.py", line 73, in get
    val = self._cache.get(key)
pylibmc.ConnectionError: error 3 from memcached_get(:1:template.cache.cleaned_articl): (0x7faf5c0cee70) CONNECTION FAILURE, ::rec() returned zero, server has disconnected,  host: memcached:11211 -> libmemcached/io.cc:484

Cache settings:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'TIMEOUT': 24 * 60 * 60, 
        'LOCATION': 'memcached:11211',
        'OPTIONS': {
            'binary': True,
            'behaviors': {
                'no_block': True,
                'tcp_nodelay': True,
                'tcp_keepalive': True,
                'connect_timeout': 2000,  # ms
                'send_timeout': 750 * 1000,  # us
                'receive_timeout': 750 * 1000,  # us
                '_poll_timeout': 2000,  # ms
                'ketama': True,
                'remove_failed': 1,
                'retry_timeout': 2,
                'dead_timeout': 30,
            }
        }
    }
}

Additional information:
Django 2.0.2
Python 3.6.4
Linux 4.9.82

Both the Django application and Memcached run on Docker containers on the same host. The error happens after a restart of Memcached (but no restart of the Django container) because pylibmc reuses connections between requests and it cannot detect that connections should be discarded because of the Docker userland proxy.

Change History (2)

comment:1 by Tim Graham, 6 years ago

Easy pickings: unset

The behavior is different on the master branch. As of e62165b898785e890661953c3b2c9c36d98aee57, {% include %} no longer silences exceptions. Do you want to propose a different behavior (such as {% cache %} silencing the exception)? I'm not sure whether or not there would be consensus to do that, but you could write to the DevelopersMailingList to get feedback.

comment:2 by Tim Graham, 6 years ago

Resolution: invalid
Status: newclosed

Marking as invalid since the cache template tag doesn't have the reported behavior.

Note: See TracTickets for help on using tickets.
Back to Top