2

I would like to use the awesome Cache Machine Django app (https://github.com/jbalogh/django-cache-machine) using Memcachier on Heroku.

From what I understand, Cache Machine does not work out of the box with Memcachier because Memcachier requires PyLibMC and SASL authentication (see https://devcenter.heroku.com/articles/memcachier#django). Cache Machine says that it supports PyLibMC -- and that all you have to do is drop in "caching.backends.memcached.PyLibMCCache" to the CACHES setting.

When you do that, though, you get this error: "error 47 from memcached_set: SERVER HAS FAILED AND IS DISABLED UNTIL TIMED RETRY"

I thought the cause of this is that caching.backends.memcached.PyLibMCCache inherits from django.core.cache.backends.memcached.PyLibMC (see https://github.com/jbalogh/django-cache-machine/blob/master/caching/backends/memcached.py), as where it should inherit from django_pylibmc.memcached.PyLibMCCache in order to work on Heroku (but this is sort of a shot in the dark).

I made my own custom cache backend that instead inherited from django_pylibmc.memcached.PyLibMCCache, but now when I check my Heroku Memcachier panel, it doesn't appear that anything I do is increasing the cache -- it's stuck at 50 mb, even though I would expect it to be increasing with each queryset.

Has anyone successfully set up Cache Machine on Heroku? If so, how'd you do it?

Jake
  • 809
  • 1
  • 8
  • 18

1 Answers1

3

I work with MemCachier. We haven't dealt directly with Cache Machine before but I just built a small app then to confirm that it works fine on Heroku and with MemCachier.

Quick background in case you are not very familiar with memcache and MemCachier. There are two protocols for talking between the client and server. One is the older ascii protocol and the other is the newer binary protocol. We at MemCachier only support the binary protocol as it supports authentication while the ascii protocol doesn't.

The mistake you are making is using caching.backends.memcached.PyLibMCCache as the cache backend. While pylibmc is the memcache client we recommend as it supports the binary protocol and sasl authentication, the cache interface that comes with Django sadly doesn't support enabling the binary protocol. So pylibmc simply goes with its default, which is the ascii protocol and fails.

You can see the ticket for Django about this issue here.

As such, at MemCachier we've always recommended that you use the alternative django-pylibmc-sasl package. This package is uses pylibmc as well, but provides a different cache interface than the one django provides that does support enabling the binary protocol and authentication. This is discussed in our documentation here.

Here is the code that I generally place in settings.py to configure Django's cache with MemCachier:'

## MemCachier Settings
## ===================
def get_cache():
  # We do this complicated cache defenition so that on a local machine (where
  # MEMCACHIER_SERVERS won't be defined), the try fails and so we use the
  # inbuilt local memory cache of django.
  try:
    os.environ['MEMCACHE_SERVERS'] = os.environ['MEMCACHIER_SERVERS'].replace(',', ';')
    os.environ['MEMCACHE_USERNAME'] = os.environ['MEMCACHIER_USERNAME']
    os.environ['MEMCACHE_PASSWORD'] = os.environ['MEMCACHIER_PASSWORD']
    return {
      'default': {
        'BACKEND': 'django_pylibmc.memcached.PyLibMCCache',
        'TIMEOUT': None,
        'BINARY': True,
        'OPTIONS': {
          'tcp_nodelay': True,
          'no_block': True,
          'tcp_keepalive': True,
          '_poll_timeout': 2000,
          'ketama': True,
          'connect_timeout': 2000,
          'remove_failed': 4,
          'retry_timeout': 2,
          'dead_timeout': 10
        }
      }
    }
  except:
    # Use django local development cache (for local development).
    return {
      'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'
      }
    }

CACHES = get_cache()

This will also make developing on your local machine easy as when MEMCACHIER_SERVERS isn't defined it'll fall back to django's simple local heap cache, avoiding the need for you to install memcache locally.

hope this helps Jake!

David Terei
  • 1,985
  • 16
  • 18
  • Thanks very much for pointing out what the problem is -- and for putting together the get_cache function. The only problem is (I think) for something like Cache Machine to work, you need to use their custom cache backends that begin with "caching.backends..." I wonder if I need to define my own backend that takes advantage of SASL? Would you have any pointers on how to get that started? – Jake Jul 16 '13 at 23:05
  • Does "think" mean you tried the above and it failed? Or this is an assumption? I'd be very surprised if cache machine had this restriction, it doesn't make any sense for it to do that. Also, in my testing I got cache machine to work with the method above. So if your's is not working could you post the error please so I can diagnose further. – David Terei Jul 18 '13 at 01:52
  • Thanks for getting back in touch. When I try your solution (this is similar to what I first tried before posting on SO, and also re-tried again now), I get no errors. However, I think it's not working because my Memcachier dashboard doesn't show the "Current Usage" or "Number of Keys" increasing at all when I would otherwise expect it to. (When I use the "caching.backends.memcached.MemcachedCache" backend with Elasticache / my own cache server, usage of the site results in increased cache usage, as expected.) – Jake Jul 18 '13 at 09:38
  • I haven't delved to deeply into the Cache Machine source (and I'm not sure I'm good enough a programmer to do so), but my understanding is that they have written custom memcached backends (i.e., what goes in the "BACKEND" setting), and using one of their backends is necessary for it to work. But, at least so far, I don't think any of their backends work with SASL -- and I'm also not sure if there's an easy fix for that. – Jake Jul 18 '13 at 09:42
  • Jake, I tested this solution against MemCachier itself so I know that it works fine with SASL authentication. I am fairly confident that something else must be wrong. It may simply be that our dashboard isn't working as expected, making you believe that the cache isn't working when it is. It's rare but occasionally our dashboard thinks you are using a different cluster then you actually are, so no cache usage ever shows up. – David Terei Jul 25 '13 at 23:42