Skip to content

Instantly share code, notes, and snippets.

@chikamichi
Last active June 6, 2016 10:07
Show Gist options
  • Save chikamichi/7491e524eadd1d9be9743d3752e184da to your computer and use it in GitHub Desktop.
Save chikamichi/7491e524eadd1d9be9743d3752e184da to your computer and use it in GitHub Desktop.
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