Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactoring classes AsyncBatchDestroyJob and AsyncBatchUpdateJob #749

Merged
merged 1 commit into from
Jul 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions app/jobs/async_batch_destroy_job.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
# frozen_string_literal: true

class AsyncBatchDestroyJob
class AsyncBatchDestroyJob < ApplicationJob
include BatchJobsLog
BATCH_SIZE = 1000
queue_as 'batch_actions'

attr_reader :model_class, :sql_query, :who_is
attr_reader :model_class, :who_is

def initialize(model_class, sql_query, who_is)
@model_class = model_class
@sql_query = sql_query
def perform(model_class, sql_query, who_is)
@model_class = model_class.constantize
@who_is = who_is
end

def perform
set_audit_log_data
begin
scoped_records = model_class.constantize.find_by_sql(sql_query + " LIMIT #{BATCH_SIZE}")
model_class.constantize.transaction do
scoped_records = @model_class.find_by_sql(sql_query + " LIMIT #{BATCH_SIZE}")
@model_class.transaction do
scoped_records.each(&:destroy!)
end
end until scoped_records.empty?
Expand Down
19 changes: 8 additions & 11 deletions app/jobs/async_batch_update_job.rb
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
# frozen_string_literal: true

class AsyncBatchUpdateJob
class AsyncBatchUpdateJob < ApplicationJob
Ivanov-Anton marked this conversation as resolved.
Show resolved Hide resolved
include BatchJobsLog
BATCH_SIZE = 1000
queue_as 'batch_actions'

attr_reader :model_class, :sql_query, :changes, :who_is
attr_reader :model_class, :sql_query, :who_is

def initialize(model_class, sql_query, changes, who_is)
@model_class = model_class
def perform(model_class, sql_query, changes, who_is)
@model_class = model_class.constantize
@sql_query = sql_query
@changes = changes
@who_is = who_is
Ivanov-Anton marked this conversation as resolved.
Show resolved Hide resolved
end

def perform
set_audit_log_data
model_class.constantize.transaction do
total_count = model_class.constantize.count_by_sql count_sql_query
@model_class.transaction do
total_count = @model_class.count_by_sql count_sql_query

(total_count.to_f / BATCH_SIZE).ceil.times do |batch_number|
offset = batch_number * BATCH_SIZE
scoped_records = model_class.constantize.find_by_sql(order_by_id_sql + " OFFSET #{offset} LIMIT #{BATCH_SIZE}")
scoped_records = @model_class.find_by_sql(order_by_id_sql + " OFFSET #{offset} LIMIT #{BATCH_SIZE}")
scoped_records.each { |record| record.update!(changes) }
end
end
Expand Down
14 changes: 14 additions & 0 deletions config/initializers/delayed_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

class Delayed::ActiveJobPlugin < Delayed::Plugin
callbacks do |lifecycle|
lifecycle.before(:invoke_job) do |job|
if job.payload_object.respond_to?(:job_data)
job.payload_object.job_data['provider_job_id'] = job.id
end
end
end
end

Delayed::Worker.plugins << Delayed::ActiveJobPlugin
Ivanov-Anton marked this conversation as resolved.
Show resolved Hide resolved
Delayed::Worker.destroy_failed_jobs = false
2 changes: 0 additions & 2 deletions config/initializers/yeti.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# frozen_string_literal: true

Delayed::Worker.destroy_failed_jobs = false

Dir[Rails.root.join('lib/ext/**/*.rb')].each { |s| require s }
Dir[Rails.root.join('lib/active_record/**/*.rb')].each { |s| require s }
Dir[Rails.root.join('lib/active_admin/**/*.rb')].each { |s| require s }
Expand Down
39 changes: 29 additions & 10 deletions lib/batch_jobs_log.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,39 @@
# frozen_string_literal: true

module BatchJobsLog
def success(job)
extend ActiveSupport::Concern

included do
around_perform :with_logic_log
end

private

def with_logic_log
Rails.logger.info { "Delayed::Worker.plugins #{Delayed::Worker.plugins}" }
result = yield
success
result
rescue StandardError => e
failure(e)
raise e
end

def success
LogicLog.create!(
source: "#{self.class} #{job.id}",
level: 0,
msg: 'Success'
)
source: "#{self.class} #{provider_job_id}",
level: 0,
msg: 'Success'
)
end

def failure(job)
def failure(error)
LogicLog.create!(
source: "#{self.class} #{job.id}",
level: 0,
msg: job.last_error
)
source: "#{self.class} #{provider_job_id}",
level: 0,
msg: "Error: #{error.message}\nchanges: #{arguments[2]}\nclass: #{arguments[0]}\nqueue: #{queue_name}\nsql: #{arguments[1]}"
)
raise error
Ivanov-Anton marked this conversation as resolved.
Show resolved Hide resolved
end

def set_audit_log_data
Expand Down
5 changes: 2 additions & 3 deletions lib/resource_dsl/acts_as_async_destroy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ def acts_as_async_destroy(model_class)
scoped_collection_action :async_destroy,
title: 'Delete batch',
if: proc { authorized?(:batch_destroy, resource_klass) } do
Delayed::Job.enqueue AsyncBatchDestroyJob.new(model_class,
AsyncBatchDestroyJob.perform_later(model_class,
scoped_collection_records.except(:eager_load).to_sql,
@paper_trail_info),
queue: 'batch_actions'
@paper_trail_info)
flash[:notice] = I18n.t('flash.actions.batch_actions.batch_destroy.job_scheduled')
head :ok
end
Expand Down
5 changes: 2 additions & 3 deletions lib/resource_dsl/acts_as_async_update.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ def acts_as_async_update(model_class, attrs_to_update)
class: 'scoped_collection_action_button ui',
form: attrs_to_update,
if: proc { authorized?(:batch_destroy, resource_klass) } do
Delayed::Job.enqueue AsyncBatchUpdateJob.new(model_class,
AsyncBatchUpdateJob.perform_later(model_class,
scoped_collection_records.except(:eager_load).to_sql,
params[:changes].permit!,
@paper_trail_info),
queue: 'batch_actions'
@paper_trail_info)
flash[:notice] = I18n.t('flash.actions.batch_actions.batch_update.job_scheduled')
head :ok
end
Expand Down
27 changes: 26 additions & 1 deletion spec/jobs/async_batch_destroy_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
include_context :init_destination, id: 2, initial_rate: 0.5
include_context :init_destination, id: 3, initial_rate: 0.7

subject { described_class.new(model_class, sql_query, who_is).perform }
subject { described_class.perform_now(model_class, sql_query, who_is) }

before :each do
stub_const('AsyncBatchDestroyJob::BATCH_SIZE', 2)
Expand Down Expand Up @@ -44,6 +44,31 @@
it { expect { subject }.to change(Routing::Destination, :count).by(-1) }
it { expect { subject }.to change(Routing::Destination.where(id: 1), :count).by(-1) }
end

context 'test LogicLog class' do
let!(:contractor) { create :vendor }
let!(:contractor_alone) { create :vendor }
let!(:gateway_group) { create :gateway_group, vendor: contractor }
let(:model_class) { 'Contractor' }

context 'should write record about' do
let(:sql_query) { Contractor.where(id: contractor_alone.id).to_sql }
it 'success performed job' do
expect { subject }.to change(LogicLog, :count).by 1
expect(LogicLog.last.msg).to start_with 'Success'
end
end

context 'when the job raise an error' do
let(:sql_query) { Contractor.all.to_sql }
it 'error performed job' do
expect do
expect { subject }.to raise_error(ActiveRecord::RecordNotDestroyed)
end.to change(LogicLog, :count).by 1
expect(LogicLog.last.msg).to start_with 'Error'
end
end
end
end
end
end
24 changes: 23 additions & 1 deletion spec/jobs/async_batch_update_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
include_context :init_destination, id: 2, initial_rate: 0.5
include_context :init_destination, id: 3, initial_rate: 0.7

subject { described_class.new(model_class, sql_query, changes, who_is).perform }
subject { described_class.perform_now(model_class, sql_query, changes, who_is) }

before :each do
stub_const('AsyncBatchUpdateJob::BATCH_SIZE', 2)
Expand Down Expand Up @@ -69,6 +69,28 @@
it { expect { subject }.to change(Routing::Destination.where(id: 1, prefix: 300), :count).by(1) }
end
end

context 'test LogicLog class' do
let(:sql_query) { Routing::Destination.all.to_sql }

context 'should write record about' do
let(:changes) { { next_interval: 4 } }
it 'success performed job' do
expect { subject }.to change(LogicLog, :count).by 1
expect(LogicLog.last.msg).to start_with 'Success'
end
end

context 'when the job raise an error' do
let(:changes) { { next_interval: 'string' } }
it 'error performed job' do
expect do
expect { subject }.to raise_error(ActiveRecord::RecordInvalid)
end.to change(LogicLog, :count).by 1
expect(LogicLog.last.msg).to start_with 'Error'
end
end
end
end
end
end