Implement a redis storage backend for job executions

I abstracted out the executions storage and made it pluggable. It still defaults to in-memory. The only thing I really had to change is moving some `RateLimit` class-level knowledge into the instance, since the `:storage` option is set on the instance when the middleware is added.

I updated the `RateLimit` spec to exercise both storage engines, and added a fairly minimal `Storage::Redis` spec to test invalid options and the race condition case and maintain 100% coverage.

Let me know if there's anything else you need in order to merge.