ontohub/ontohub

View on GitHub
lib/state_updater.rb

Summary

Maintainability
A
2 hrs
Test Coverage
require 'sidekiq/cli'

module StateUpdater
  extend ActiveSupport::Concern

  included do
    scope :state, ->(*states){
      where state: states.map(&:to_s)
    }
  end

  def after_failed
    # override if necessary
  end

  def do_or_set_failed(updating_klass = nil, &block)
    raise ArgumentError.new('No block given.') unless block_given?

    begin
      yield
    rescue Exception => e
      begin
        if Sidekiq::Shutdown === e
          # Sidekiq requeues the current job automatically
          update_state! :pending
        else
          if updating_klass
            updating_klass.new(self, :failed, e.message).call
          else
            update_state! :failed, e.message
          end
          after_failed
        end
      rescue Exception => ee
        # Can really happen (SQL Exceptions, etc.)
        error  = "Nested exception on updating state of #{self.class} #{id}\n"
        error << "#{ee.class}: #{ee}\n  " << ee.backtrace.join("\n  ") << "\n"
        error << "#{e.class}: #{e}\n  "   <<  e.backtrace.join("\n  ")

        # Update attributes without any callbacks
        self.class.where(id: id).update_all \
          state:            'failed',
          state_updated_at: Time.now,
          last_error:       error

        # re-raise
        raise
      end
      raise
    end
  end

  def update_state!(state, error_message = nil)
    update_attributes!({state: state.to_s,
                        state_updated_at: Time.now,
                        last_error: error_message},
                        without_protection: true)
  end
end