Skip to content

Instantly share code, notes, and snippets.

@chikamichi
Last active Jun 6, 2016
Embed
What would you like to do?
Wrapper around DelayedJob (basic Job system for Rails)
require 'ostruct'
# Tiny wrapper around (custom) delayed jobs.
# @see https://github.com/collectiveidea/delayed_job
# @see https://github.com/collectiveidea/delayed_job#custom-jobs
#
# Create a new job by inheriting from Base Job:
#
# # app/jobs/some_task_job.rb
# class SomeTask < BaseJob
# def perform(args)
# # do stuff…
# end
# end
#
# Usage:
#
# SomeTask.new(param1: 'param1', param2: 'param2')
# SomeTask.new(param1: 'param1', param2: 'param2', priority: 2)
#
# A job is enqueued as soon as it's created. If you wish to postpone the job,
# use #build instead of #new. To enqueue the job, call #run.
#
# job = SomeTask.build(param1: 'param1', param2: 'param2')
# # stuff…
# job.postponed? # => true
# # stuff…
# job.run
# job.postponed? # => false
#
class BaseJob < OpenStruct
def initialize(data = {})
@__postponed = data.delete(:__postponed) || false
super(data)
enqueue! unless @__postponed
end
def self.build(data = {})
new(data.merge(__postponed: true))
end
def run
if postponed?
enqueue!
return true
else
return false
end
end
def postponed?
@__postponed
end
protected
def enqueue!
@__postponed = false
Delayed::Job.enqueue(self, priority: inner_priority)
end
def inner_priority
priority || 0
end
end
require 'rails_helper'
RSpec.describe BaseJob do
before do
allow(Delayed::Job).to receive(:enqueue).and_return(true)
end
describe 'the class' do
it 'is instanciable' do
expect(subject).to be_an_instance_of(described_class)
end
it 'is an OpenStruct wrapper' do
expect(subject.class.superclass).to eq OpenStruct
end
it 'does not respond to #perform' do
# Actual jobs must implement such a method, as per Delayed::Job's API.
expect(subject).to_not respond_to(:perform)
end
it 'responds to #build' do
expect(described_class).to respond_to(:build)
end
end
describe '.new' do
it 'immediately enqueues the job' do
expect_any_instance_of(BaseJob).to receive(:enqueue!)
BaseJob.new
end
it 'reports itself as not postponed' do
expect(subject.postponed?).to be false
end
end
describe '.build' do
subject { BaseJob.build }
it 'creates a new job' do
expect(subject).to be_an_instance_of(described_class)
end
it 'does not immediately enqueue the job' do
expect_any_instance_of(BaseJob).to_not receive(:enqueue!)
BaseJob.build
end
it 'reports itself as postponed' do
expect(subject.postponed?).to be true
end
end
describe '#run' do
context 'called on a postponed job' do
subject { BaseJob.build }
it 'enqueues the job' do
expect(subject).to receive(:enqueue!)
subject.run
end
it 'returns true' do
expect(subject.run).to be true
end
it 'marks the job as enqueued' do
expect { subject.run }.to change(subject, :postponed?).from(true).to(false)
end
end
context 'called on an immediate job' do
it 'is a no-op' do
expect(subject).to_not receive(:enqueue!)
subject.run
end
it 'returns false' do
expect(subject.run).to be false
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment