jdriscoll/django-imagekit — pull request #89 by matthewwithanm (2012-02-02 06:20:35+00:00)
Title: Cache State Backends

Alright, here's my first crack at what @cyberdelia, @bryanveloso, and I were talking about in #88. Essentially, it's my solution to #74, #75, #81, and #88. In summary, `ImageSpec`s are no longer directly responsible for creating and deleting cached images. Instead they delegate the responsibility to "cache state backends."

Cache state backends must implement two methods: `invalidate()` and `validate()`. The default backend maintains the current behavior: invalidating an image deletes it, and validating it creates the file (if it does not already exist). This behavior is very safe (which is why I think it makes a good default) but, as @mkai noted in #81, it can be prohibitively slow for certain file storage backends. This new setup allows him to define a much more optimistic backend that, for example, could immediately regenerate cache images on invalidation and define validation as a no-op. Since images are generally infrequently invalidated and frequently validated, this system would probably work out much better for him.

Similarly, @davelowe could use a custom cache state backend to queue the creation of images via celery instead of having the processing of the image hold up his page loads.

API Changes
-----------

I ended up removing the `pre_cache` argument from the `ImageSpec` constructor. The main reason for this is that cache state backends provide a much more powerful mechanism for controlling this behavior. @bryanveloso's :+1: pushed me over the edge. I put in an exception to warn anybody who migrates.

Since the decision about which cache state backend to use will likely be tightly coupled to your choice of storage, I wanted to make it very similar to use. Therefore, there are two ways to set a cache state backend:

1. Pass an instance to the `ImageSpec` constructor (like the `storage` kwarg)
2. Set `IMAGEKIT_DEFAULT_CACHE_STATE_BACKEND` in settings.py (like `DEFAULT_FILE_STORAGE`)

In place of `ikflush`, we now have two shiny new management commands: `ikcacheinvalidate` and `ikcachevalidate`. (The old `ikflush` was dependent on `pre_cache` and that wasn't going to cut it anymore.) They work pretty much exactly how you'd expect. `ikcachevalidate` also accepts a `--force` flag which makes it behave like `ikflush` did when `pre_cache` was true; using this flag will cause each file to be invalidated and then immediately validated. (This is pretty much the same as running `ikcacheinvalidate` and then `ikcachevalidate`, except that would invalidate all files before validating any of them.)

Finally, IK metadata ("_ik") is now bound to each model instance. I doubt anybody who's not hacking around in the guts of IK will even notice this change, but it makes acquiring a list of bound filefields a little prettier.

So
--

This is another nontrivial change, so I figured I'd submit a pull request for us to discus. So let's hear your thoughts! And, if you have some free time after that, here's some other stuff to do:

1. Test it out (I haven't really tested much at all)
2. Write some cache state backends! It would be nice if we could bundle a few with IK. The optimistic one I mentioned earlier might be a candidate.
3. Docs, please!