class Sufia::UserStatImporter

Constants

UserRecord

Public Class Methods

new(options = {}) click to toggle source
# File lib/sufia/models/stats/user_stat_importer.rb, line 5
def initialize(options = {})
  @verbose = options[:verbose]
  @logging = options[:logging]
  @delay_secs = options[:delay_secs].to_f
  @number_of_retries = options[:number_of_retries].to_i
end

Public Instance Methods

import() click to toggle source
# File lib/sufia/models/stats/user_stat_importer.rb, line 12
def import
  log_message('Begin import of User stats.')
  sorted_users.each do |user|
    start_date = date_since_last_cache(user)

    # this user has already been processed today continue without delay
    next if start_date.to_date >= Date.today

    stats = {}
    file_ids_for_user(user).each do |file_id|
      view_stats = rescue_and_retry("Retried FileViewStat on #{user} for file #{file_id} too many times.") { FileViewStat.statistics(file_id, start_date, user.id) }
      stats = tally_results(view_stats, :views, stats) unless view_stats.blank?
      delay

      dl_stats = rescue_and_retry("Retried FileDownloadStat on #{user} for file #{file_id} too many times.") { FileDownloadStat.statistics(file_id, start_date, user.id) }
      stats = tally_results(dl_stats, :downloads, stats) unless dl_stats.blank?
      delay
    end

    create_or_update_user_stats(stats, user)
  end
  log_message('User stats import complete.')
end
sorted_users() click to toggle source

Returns an array of users sorted by the date of their last stats update. Users that have not been recently updated will be at the top of the array.

# File lib/sufia/models/stats/user_stat_importer.rb, line 39
def sorted_users
  users = []
  ::User.find_each do |user|
    users.push(UserRecord.new(user.id, user.user_key, date_since_last_cache(user)))
  end
  users.sort { |a, b| a.last_stats_update <=> b.last_stats_update }
end

Private Instance Methods

create_or_update_user_stats(stats, user) click to toggle source
# File lib/sufia/models/stats/user_stat_importer.rb, line 108
def create_or_update_user_stats(stats, user)
  stats.each do |date_string, data|
    date = Time.zone.parse(date_string)

    user_stat = UserStat.where(user_id: user.id).where(date: date).first
    user_stat ||= UserStat.new(user_id: user.id, date: date)

    user_stat.file_views = data[:views] || 0
    user_stat.file_downloads = data[:downloads] || 0
    user_stat.save!
  end
end
date_since_last_cache(user) click to toggle source
# File lib/sufia/models/stats/user_stat_importer.rb, line 69
def date_since_last_cache(user)
  last_cached_stat = UserStat.where(user_id: user.id).order(date: :asc).last

  if last_cached_stat
    last_cached_stat.date + 1.day
  else
    Sufia.config.analytic_start_date
  end
end
delay() click to toggle source
# File lib/sufia/models/stats/user_stat_importer.rb, line 49
def delay
  sleep @delay_secs
end
file_ids_for_user(user) click to toggle source
# File lib/sufia/models/stats/user_stat_importer.rb, line 79
def file_ids_for_user(user)
  ids = []
  ::GenericFile.find_in_batches("#{Solrizer.solr_name('depositor', :symbol)}:\"#{user.user_key}\"", fl: "id") do |group|
    ids.concat(group.map { |doc| doc["id"] })
  end
  ids
end
log_message(message) click to toggle source
# File lib/sufia/models/stats/user_stat_importer.rb, line 121
def log_message(message)
  puts message if @verbose
  Rails.logger.info "#{self.class}: #{message}" if @logging
end
rescue_and_retry(fail_message) { || ... } click to toggle source
# File lib/sufia/models/stats/user_stat_importer.rb, line 53
def rescue_and_retry(fail_message)
  retry_count = 0
  begin
    return yield
  rescue StandardError => e
    retry_count += 1
    if retry_count < @number_of_retries
      delay
      retry
    else
      log_message fail_message
      log_message "Last exception #{e}"
    end
  end
end
tally_results(file_stats, stat_name, total_stats) click to toggle source

For each date, add the view and download counts for this file to the view & download sub-totals for that day. The resulting hash will look something like this: {“2014-11-30 00:00:00 UTC” => {:views=>2, :downloads=>5},

"2014-12-01 00:00:00 UTC" => {:views=>4, :downloads=>4}}
# File lib/sufia/models/stats/user_stat_importer.rb, line 92
def tally_results(file_stats, stat_name, total_stats)
  file_stats.each do |stats|
    # Exclude the stats from today since it will only be a partial day's worth of data
    break if stats.date == Date.today

    date_key = stats.date.to_s
    old_count = total_stats[date_key] ? total_stats[date_key].fetch(stat_name) { 0 } : 0
    new_count = old_count + stats.method(stat_name).call

    old_values = total_stats[date_key] || {}
    total_stats.store(date_key, old_values)
    total_stats[date_key].store(stat_name, new_count)
  end
  total_stats
end