Background jobs in pieces
Hegedüs Zoltán
The problem
class Topic < ActiveRecord::Base
has_many :posts
end
class Post < ActiveRecord::Base
belongs_to :topic
end
topic = Topic.find(1)
result = topic.title + ': ' + topic.posts.map do |post|
"#{post.title}: #{post.body}"
end.join(';')
puts result
Topic
Post
Post
Post
posts
Export classes
class Export < ActiveRecord::Base
belongs_to :target, polymorphic: true
after_commit :enqueue_export_job, on: :create
def enqueue_export_job
"Jobs::#{self.class}".constantize.perform_later(self)
end
end
class Export::TopicExport < Export
include Export::HasChildren
has_many :post_exports,
class_name: 'Export::PostExport',
inverse_of: :parent,
foreign_key: :parent_id
alias topic target
private
def compose_child_content
Jobs::TopicExport::Composer.perform_later(self)
end
end
class Export::PostExport < Export
include HasParent
alias post target
end
TopicExport
post_exports
PostExport
PostExport
PostExport
Topic
Post
Post
Post
target
target
Export-export relationships
module Export::HasChildren
extend ActiveSupport::Concern
included do
has_many :child_exports,
class_name: 'Export',
foreign_key: :parent_id
end
def child_export_complete
unless child_exports.where.not(status: :complete).exists?
compose_child_content
end
end
end
module Export::HasParent
extend ActiveSupport::Concern
included do
belongs_to :parent,
class_name: 'Export'
after_commit :notify_parent_of_status_change,
on: :update
end
def notify_parent_of_status_change
parent.child_export_complete if status == 'complete'
end
end
Export
children
Export
Export
Export
parent
Background jobs
class Jobs::TopicExport < ActiveJob::Base
def perform(export)
export.topic.posts.each do |post|
export.post_exports.create!(target: post)
end
end
end
class Jobs::PostExport < ActiveJob::Base
def perform(export)
@export = export
export.update_attributes!(status: :complete, result: content)
end
attr_reader :export
def content
"#{export.post.title}: #{export.post.body}"
end
end
class Jobs::TopicExport::Composer < ActiveJob::Base
def perform(export)
@export = export
export.update_attributes!(status: :complete, result: content)
end
attr_reader :export
def content
export.topic.title + ':' +
export.post_exports.map(&:result).join(";")
end
end
TopicExport
post_exports
PostExport
PostExport
PostExport
Topic
Post
Post
Post
target
target
Background jobs
class Jobs::TopicExport < ActiveJob::Base
def perform(export)
my_splittable_config.each do |config_fragment|
export.my_child_export.create!(settings: config_fragment)
end
end
end
TopicExport
my_child_exports
PostExport
PostExport
PostExport
Solution
topic = Topic.find(1)
Topic
Post
Post
Solution
topic = Topic.find(1)
export = Export::TopicExport.create!(target: topic)
TopicExport
Topic
Post
Post
Solution
topic = Topic.find(1)
export = Export::TopicExport.create!(target: topic)
# tik
TopicExport
Topic
Post
Jobs::TopicExport
Post
PostExport
PostExport
Solution
topic = Topic.find(1)
export = Export::TopicExport.create!(target: topic)
# tik-tak
TopicExport
Jobs::PostExport
Topic
Post
Jobs::TopicExport
Post
PostExport
PostExport
PostExport
Post
Jobs::PostExport
PostExport
Post
Solution
topic = Topic.find(1)
export = Export::TopicExport.create!(target: topic)
# tik-tak
TopicExport
Jobs::PostExport
Topic
Post
Jobs::TopicExport
Post
PostExport
PostExport
PostExport
Post
Jobs::PostExport
PostExport
Post
Solution
topic = Topic.find(1)
export = Export::TopicExport.create!(target: topic)
# tik-tak
TopicExport
Jobs::PostExport
Topic
Post
Jobs::TopicExport
Post
PostExport
PostExport
PostExport
Post
Jobs::PostExport
PostExport
Post
Solution
topic = Topic.find(1)
export = Export::TopicExport.create!(target: topic)
# tik-tak-tik
TopicExport
Jobs::PostExport
Topic
Post
Jobs::TopicExport
Post
PostExport
PostExport
PostExport
Post
Jobs::PostExport
PostExport
Post
Jobs::TopicExport::Composer
TopicExport
PostExport
PostExport
Topic
Solution
topic = Topic.find(1)
export = Export::TopicExport.create!(target: topic)
# tik-tak-tik-tak
puts export.reload.result
TopicExport
Jobs::PostExport
Topic
Post
Jobs::TopicExport
Post
PostExport
PostExport
PostExport
Post
Jobs::PostExport
PostExport
Post
Jobs::TopicExport::Composer
TopicExport
PostExport
PostExport
TopicExport
.result =
background-jobs
By hegedus-zoltan
background-jobs
- 568