docbrown/app/models/data_update_script.rb
rhymes 582d32393c
Small ActiveRecord optimizations: begone race conditions and hello bulk insert (#8436)
* Replace PollSkips find_or_create_by with create_or_find_by

* Use insert_all to add users to a channel in bulk

* Use bulk insert for DataUpdateScript and set private what shall be private

* oops
2020-06-15 17:57:14 +02:00

72 lines
1.7 KiB
Ruby

class DataUpdateScript < ApplicationRecord
DIRECTORY = Rails.root.join("lib/data_update_scripts").freeze
NAMESPACE = "DataUpdateScripts".freeze
STATUSES = { enqueued: 0, working: 1, succeeded: 2, failed: 3 }.freeze
default_scope { order(file_name: :asc) }
enum status: STATUSES
validates :file_name, uniqueness: true
class << self
def scripts_to_run
ids = load_script_ids
enqueued.where(id: ids)
end
# true if there are more files on disk or any scripts to run, false otherwise
def scripts_to_run?
db_scripts = DataUpdateScript.pluck(:file_name, :status).to_h
return true if filenames.size > db_scripts.size
return true if db_scripts.values.any? { |s| s.to_sym == :enqueued }
false
end
private
def filenames
Dir.glob("*.rb", base: DIRECTORY).map do |f|
Pathname.new(f).basename(".rb").to_s
end
end
def load_script_ids
# insert new scripts in bulk
now = Time.current
scripts_params = filenames.map do |fn|
{ file_name: fn, created_at: now, updated_at: now }
end
DataUpdateScript.insert_all(scripts_params)
DataUpdateScript.pluck(:id)
end
end
def mark_as_run!
update!(run_at: Time.current, status: :working)
end
def mark_as_finished!
update!(finished_at: Time.current, status: :succeeded)
end
def mark_as_failed!
update!(finished_at: Time.current, status: :failed)
end
def file_path
"#{self.class::DIRECTORY}/#{file_name}.rb"
end
def file_class
"#{self.class::NAMESPACE}::#{parsed_file_name.camelcase}".safe_constantize
end
private
def parsed_file_name
file_name.match(/\d{14}_(.*)/)[1]
end
end