My general thoughts on Resque Next is that it should be more of a protocol and an interface than an end-all-be-all solution for delayed work in Ruby, that it should provide at least one implementation for each of the interfaces, but that it should leave further implementation up to third-parties and separate include-if-you-want-it gems (that may be published to either the resque org or elsewhere).
This includes the dependency on Redis. When a consumer out-grows Redis and needs to use a queueing service that has actual, non-emulated queueing semantics, they shouldn't have to rewrite all of their worker code and start over from scratch; when they become entirely IO-bound and need thread-based workers, they should be able to swap out the worker class and everything should just work.
And I don't know if we can get there in a step-by-step, one-thing-at-a-time refactor. Maybe.
Here are some pseudo-code thoughts on interfaces and boundaries:
module Resque
# passthrough to Redis::Backend
def self.new(*args, &block)
Backend.new(*args, &block)
end
module QueueProvider
# provides interface for *all* queueing semantics
# (queue, queue_at, reserve, ack, fail, heartbeat, etc.)
# and queue introspection/manipulation.
# (list, count, move, drop)
end
class QueueProvider::Redis
include QueueProvider
# provides implementation of QueueProvider
# with emulated queueing semantics via redis
end
module Coder
# provide interface for *all* encode/decode
end
class Coder::JSON
include Coder
# provides implementation of Coder via JSON
end
class Backend
# In my mind, the Backend is the core of everything, the instance that
# gets passed around to the workers that use it, the queue providers,
# the everything. It holds a config hash or object and makes decisions
# based on that configuration.
def intialize(config = {})
@config = config.dup
end
def queue_provider
@queue_provider ||= begin
provider_class = @config.fetch(:queue_provider) { QueueProvider::Redis }
provider_class.new(self)
end
end
# and then use Forwardable to delegate queueing semantics to
# the queue provider.
def coder
@coder ||= begin
coder_class = @config.fetch(:coder) { Coder::JSON }
coder_class.new(self)
end
end
def worker(queues)
@worker_class ||= @config.fetch(:worker) { Worker::Forked }
@worker_class.new(self, queues)
end
end
module Worker
# provides interface for a worker.
end
class Worker::Forked
include Worker
# provides implementation of Worker, near-identical to the current
# 1-x implementation.
end
end