module JamRuby class ResultStub extend ActiveModel::Naming extend ActiveModel::Translation include ActiveModel::Validations include ActiveModel::Conversion attr_accessor :vals def initialize(vals) @vals = vals end def self.stubs(sql) ActiveRecord::Base.connection.execute(sql).collect { |rr| self.new(rr) } end def persisted?; false; end end # Temporary Tables created by this class: # tmp_candidate_sessions # ---------------------- # # These are 'open' sessions that have any open slots left, and fall within a certain start time. # The session creator must also have a locidispid. # # session_id - music_session.id # creator_id - music_session.user_id # creator_score_idx - this is the creator's users.last_jam_locidispid # instrument_id - instruments that are open as gleamed from the RSVP. If this is NULL, it means 'ANY INSTRUMENT' # invited_user_id - the ID of a user who was invited. Can be NULL. # # tmp_candidate_recipients # ------------------------ # # These are musicians, that allow email notifications, that have an instrument which matches the session's open RSVP slot's instrument. # The musician must also have a locidispid. # # receiver_id - user ID that could be in the session # receiver_score_idx - the user's last_jam_locidispid # instrument_id - the user's matching instrument for a open session slot. If this is NULL, it means 'ANY INSTRUMENT' # invited_user_id # # tmp_matches # ----------- # # These are 'candidate_recipients' that have a decent enough score with the creator of the music sessions in tmp_candidate_sessions # # receiver_id - the user.id that should receive an Daily Session email # session_id - the music_session.id for the email # latency - the score.score between the creator and the candidate (needs to be full score soon) class EmailBatchScheduledSessions < EmailBatchPeriodic BATCH_SIZE = 500 SINCE_DAYS = 2 MIN_HOURS_START = 2 ENV_MAX_LATENCY = 'env_max_latency' ENV_QUERY_LIMIT = 'env_query_limit' SNAPSHOT_QUERY_LIMIT = '500' def self.refresh_snapshot! self.where(:aasm_state => 'snapshot').limit(1).first.try(:destroy) oo = self.create oo.snapshoting! oo end def self.subject "New sessions have been scheduled that may be a good match for you!" end def earliest_session_create_time time_since_last_batch(SINCE_DAYS) end def latest_session_create_time self.created_at end def earliest_session_start_time self.created_at + MIN_HOURS_START.hours end def snapshot_eligible_sessions rr = ActiveRecord::Base.connection.execute("SELECT COUNT(*) AS num FROM tmp_candidate_sessions") [0 < rr.count ? rr[0]['num'].to_i : 0, ResultStub.stubs("SELECT * FROM tmp_candidate_sessions")] end def snapshot_eligible_recipients rr = ActiveRecord::Base.connection.execute("SELECT COUNT(*) AS num FROM tmp_candidate_recipients") [0 < rr.count ? rr[0]['num'].to_i : 0, ResultStub.stubs("SELECT * FROM tmp_candidate_recipients")] end def snapshot_scored_recipients rr = ActiveRecord::Base.connection.execute("SELECT COUNT(*) AS num FROM tmp_matches") [0 < rr.count ? rr[0]['num'].to_i : 0, ResultStub.stubs("SELECT * FROM tmp_matches")] end def take_snapshot _load_recipients _count_recipients self.update_attribute(:test_emails, @counters.inspect) end def fetch_recipients(per_page=BATCH_SIZE) objs = [] _load_recipients @per_page = per_page num_recip = _select_scored_recipients(-1) loops = (num_recip / @per_page) + (num_recip % @per_page) - 1 0.upto(loops) do |nn| offset = nn * @per_page # now just get the sessions/latency for each distinct mail recipient _select_scored_recipients(offset).each do |result| receiver = User.find_by_id(result['receiver_id']) sessions = MusicSession.select("music_sessions.*, tmp_matches.latency") .joins("INNER JOIN tmp_matches ON tmp_matches.session_id = music_sessions.id") .where(["tmp_matches.receiver_id = ?", receiver.id]) .order('tmp_matches.latency') .limit(20) .includes([:genre, :creator]) block_given? ? yield(receiver, sessions) : objs << [receiver, sessions] end end objs end def deliver_batch_sets! self.opt_in_count = 0 self.fetch_recipients do |receiver, sessions_and_latency| self.opt_in_count += 1 bset = EmailBatchSet.scheduled_session_set(self, receiver, sessions_and_latency) UserMailer.scheduled_session_daily(receiver, sessions_and_latency).deliver_now end self.test_emails = _count_recipients.inspect self.sent_count = self.opt_in_count self.save self.did_batch_run! end def self.send_daily_session_batch oo = self.create oo.deliver_batch oo end private # inserts eligible sessions to temp table def _collect_eligible_sessions ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS tmp_candidate_sessions") limit_sql = (self.snapshot? && 0 < ENV[ENV_QUERY_LIMIT].to_i) ? "LIMIT #{ENV[ENV_QUERY_LIMIT]}" : '' sql =< '#{earliest_session_create_time}' AND msess.created_at < '#{latest_session_create_time}' AND scheduled_start >= '#{earliest_session_start_time}' #{limit_sql} SQL ActiveRecord::Base.connection.execute(sql) end def _collect_eligible_recipients ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS tmp_candidate_recipients").check limit_sql = (self.snapshot? && 0 < ENV[ENV_QUERY_LIMIT].to_i) ? "LIMIT #{ENV[ENV_QUERY_LIMIT]}" : '' # load eligible recipients into tmp table sql =< offset sql = "SELECT COUNT(DISTINCT receiver_id) AS num FROM tmp_matches" rr = ActiveRecord::Base.connection.execute(sql) return 0 < rr.count ? rr[0]['num'].to_i : 0 else sql =< session_count, :receiver_candidates => receiver_candidate_count, :receiver_match => receiver_match_count } end end end