Opened 7 years ago

Closed 4 years ago

#28342 closed Cleanup/optimization (needsinfo)

Make PyLibMCCache backend catch exceptions when memcached server is down

Reported by: Julian Andrews Owned by: Joel Andrews
Component: Core (Cache system) Version: 3.0
Severity: Normal Keywords: memcached cache pylibmc
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

If your memcached server is down, pylibmc will raise a pylibmc.ConnectionError or pylibmc.ServerDown exception for all operations. This is different from the behavior of the python-memcached package (see http://sendapatch.se/projects/pylibmc/misc.html). However, the PyLibMCCache cache backend does nothing to catch these errors. As a result, the behavior is different from the MemcachedCache backend which fails silently.

This behavior is particularly problematic for fragment caches which obviously shouldn't raise an exception. In any case, it seems pretty clear that both backends should have the same behavior.


Steps to reproduce:

  1. Setup a Django app CACHES set to use PyLibMCCache:
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'LOCATION': '127.0.0.1:11211',
    }
}
  1. With no active memcached server open a shell and run:
from django.core.cache import cache
cache.get('foo')

pylibmc will raise an exception. Using MemcachedCache, cache.get will instead return None.

Change History (8)

comment:1 by Julian Andrews, 7 years ago

My current workaround is subclass of PyLibMCCache which catches pylibmc.ConnectionError or pylibmc.ServerDown for each operation, and then does whatever MemcachedCache is doing in each case. I'd be happy to turn that into a PR for a change to PyLibMCCache if that approach is good. I'm not sure if there are other sorts of exceptions that pylibmc raises that should also be handled, but I think it would be a good start.

comment:2 by Tim Graham, 7 years ago

Summary: PyLibMCCache throwing exceptions when memcached server is downMake PyLibMCCache backend catch exceptions when memcached server is down
Triage Stage: UnreviewedAccepted
Type: BugCleanup/optimization

It might be worth looking at django_pylibmc and emulating the behavior there.

in reply to:  2 comment:3 by Julian Andrews, 7 years ago

Owner: changed from nobody to Julian Andrews
Status: newassigned

comment:4 by Julian Andrews, 7 years ago

I've written up a patch here: https://github.com/django/django/pull/8681. I looked at the django-pylibmc code, and it was very similar to what I was already doing, but there are a few differences.

First, django-pylibmc seems to be returning False to indicate failure for a bunch of methods (and None to indicate success). Given that that differs from the MemcachedCache behavior, and that the False vs. None distinction is sort of confusing, I decided to stick with the default behavior. I actually like the idea of a return value that indicates if cache fetch was successful, but in that case, the relevant methods should probably always return True or False, and that behavior should be consistent across backends. I decided not to do that as part of this PR.

Second, django-pylibmc includes logging of errors. I actually *really* like that, but again, it's not consistent with the other backend behavior, so I didn't include that. I could add logging though I'm not really that familiar with the django logging conventions, so some pointers on that would be helpful!

Third, django-pylibmc was never catching ConnectionErrors. As far as I can tell, when the memcached server goes down, the first error gets a ConnectionError and then later ones throw ServerDown so I'm pretty sure we need to catch both.

comment:5 by Tim Graham, 7 years ago

Has patch: set
Patch needs improvement: set

comment:6 by Joel Andrews, 4 years ago

Owner: changed from Julian Andrews to Joel Andrews
Patch needs improvement: unset
Version: 1.113.0

Since this ticket and its corresponding pull request (https://github.com/django/django/pull/8681) have gone stale, I've reassigned this to myself and submitted a new, up-to-date pull request for 3.0: https://github.com/django/django/pull/12893.

comment:7 by Joel Andrews, 4 years ago

No relation to the ticket reporter. :D

comment:8 by Mariusz Felisiak, 4 years ago

Resolution: needsinfo
Status: assignedclosed

I'm not sure about catching all kind of exceptions or even pylibmc.ConnectionError or pylibmc.ServerDown. Consistency between different backends for the same serves is not a strong argument for me. pylibmc policy is strongly expressed in the docs. Folks using different libraries can expect different behaviors, and you can always change your stack.

I think we should go back to the DevelopersMailingList and reach a strong consensus to move it forward.

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