mysociety/alaveteli

View on GitHub
app/models/user/spreadable_alerts.rb

Summary

Maintainability
A
0 mins
Test Coverage
# Handles spreading alerts over the day so that we have a more even server load.
module User::SpreadableAlerts
  extend ActiveSupport::Concern

  included do
    after_initialize :set_alert_times
  end

  class_methods do
    # Used for default values of last_daily_track_email
    def random_time_in_last_day
      Time.zone.now - rand(24.hours).seconds
    end

    # Alters last_daily_track_email for every user, so alerts will be sent
    # spread out fairly evenly throughout the day, balancing load on the server.
    # This is intended to be called by hand from the Ruby console. It will mean
    # quite a few users may get more than one email alert the day you do it, so
    # have a care and run it rarely.
    #
    # This SQL statement is useful for seeing how spread out users are at the
    # moment:
    #
    # SELECT extract(hour from last_daily_track_email) AS h, COUNT(*)
    # FROM users
    # GROUP BY extract(hour from last_daily_track_email)
    # ORDER BY h;
    def spread_alert_times_across_day
      find_each do |user|
        user.update!(last_daily_track_email: random_time_in_last_day)
      end

      nil # so doesn't print all users on console
    end
  end

  private

  def set_alert_times
    return unless new_record?

    # make alert emails go out at a random time for each new user, so
    # overall they are spread out throughout the day.
    self.last_daily_track_email = self.class.random_time_in_last_day

    # Make daily summary emails go out at a random time for each new user
    # too, if it's not already set
    self.daily_summary_hour ||= self.class.random_time_in_last_day.hour
    self.daily_summary_minute ||= self.class.random_time_in_last_day.min
  end
end