Investigate Resque.enqueue accepting an Active Job class
Resque.enqueue(SomeActiveJobClass, *args) raises Resque::NoQueueError today, because queue_from_class looks for @queue or queue and Active Job names its queue queue_name.
Worth deciding whether that should work at all, and if so, doing it properly.
Why the obvious fix is not the fix. Making queue_from_class read queue_name was tried in #1965 and closed. An Active Job class does not respond to .perform, and a worker performs a job by calling payload_class.perform(*args) — so supplying a queue only gets the job accepted and then failed in a worker with NoMethodError. It converts a fail-fast at the call site into a broken job on the failed queue.
What the adapter already does right. Since 3.0 the Active Job adapter lives in our own tree (lib/active_job/queue_adapters/resque_adapter.rb). It never enqueues the user's class:
def enqueue(job)
JobWrapper.instance_variable_set(:@queue, job.queue_name)
Resque.enqueue_to job.queue_name, JobWrapper, job.serialize
endThe queue comes from job.queue_name — the instance, so queue_as { } blocks resolve — and JobWrapper.perform calls ActiveJob::Base.execute.
The shape of a real implementation would be for Resque.enqueue to detect an ActiveJob::Base subclass and route it through that same path: instantiate the job with the given args, then hand it to the adapter rather than enqueueing the class. Roughly what perform_later would have done.
Open questions worth settling before writing any of it:
- Should resque do this at all? Anyone with Active Job configured can call
perform_later. The case for it is ergonomics and third-party callers that only know how to hand resque a class and args (see resque/resque-scheduler#824). The case against is a second enqueue path into Active Job that has to stay in step with the adapter. - What about
dequeue/destroy? They also go throughqueue_from_class. A job enqueued asJobWrapperwith a serialized payload cannot be matched by class and args the way a plain resque job can, soResque.dequeue(MyActiveJob, *args)would need real thought or an explicit refusal. - Should an unsupported case stay loud? Whatever we do, an Active Job class that we cannot enqueue correctly should keep raising at the call site rather than producing a job that fails later.
Related: #1713 (the 2020 request), #1965 (closed attempt), resque/resque-scheduler#824 (the downstream case that motivated it).
Source: resque/resque