100 lines
2.2 KiB
Ruby
100 lines
2.2 KiB
Ruby
class Mailings::HourlyThroughput
|
|
HOUR = 1.hour
|
|
RECENT = 15.minutes
|
|
DEFAULT_RANGE = "12h"
|
|
RANGES = {
|
|
"12h" => { grain: :hour, periods: 12, short: "12h", label: "ultime 12 ore" },
|
|
"24h" => { grain: :hour, periods: 24, short: "24h", label: "ultime 24 ore" },
|
|
"7d" => { grain: :day, periods: 7, short: "7g", label: "ultima settimana" }
|
|
}.freeze
|
|
|
|
def self.normalize_range(value)
|
|
key = value.to_s
|
|
RANGES.key?(key) ? key : DEFAULT_RANGE
|
|
end
|
|
|
|
def initialize(project, now: Time.current, range: DEFAULT_RANGE)
|
|
@project = project
|
|
@now = now
|
|
@range_key = self.class.normalize_range(range)
|
|
end
|
|
|
|
attr_reader :range_key
|
|
|
|
def range
|
|
RANGES.fetch(@range_key)
|
|
end
|
|
|
|
def sent
|
|
@sent ||= sent_since(HOUR)
|
|
end
|
|
|
|
def recent_sent
|
|
@recent_sent ||= sent_since(RECENT)
|
|
end
|
|
|
|
def failed
|
|
@failed ||= recipients.failed.where(updated_at: (@now - HOUR)..@now).count
|
|
end
|
|
|
|
def drained
|
|
sent + failed
|
|
end
|
|
|
|
def history
|
|
@history ||= buckets_for_range
|
|
end
|
|
|
|
def history_total
|
|
history.sum { |bucket| bucket[:count] }
|
|
end
|
|
|
|
def history_max
|
|
[history.map { |bucket| bucket[:count] }.max, 1].max
|
|
end
|
|
|
|
private
|
|
|
|
def buckets_for_range
|
|
from, step = history_origin
|
|
keyed = recipients.sent
|
|
.where(sent_at: from..@now)
|
|
.pluck(:sent_at)
|
|
.each_with_object(Hash.new(0)) do |sent_at, counts|
|
|
counts[bucket_at(sent_at)] += 1
|
|
end
|
|
|
|
range[:periods].times.map do |index|
|
|
at = from + (step * index)
|
|
{ at: at, count: keyed[at] || 0, label: bucket_label(at) }
|
|
end
|
|
end
|
|
|
|
def history_origin
|
|
if range[:grain] == :day
|
|
from = (@now.to_date - (range[:periods] - 1)).in_time_zone.beginning_of_day
|
|
[from, 1.day]
|
|
else
|
|
from = (@now - (range[:periods] - 1).hours).beginning_of_hour
|
|
[from, 1.hour]
|
|
end
|
|
end
|
|
|
|
def bucket_at(sent_at)
|
|
time = sent_at.in_time_zone
|
|
range[:grain] == :day ? time.beginning_of_day : time.beginning_of_hour
|
|
end
|
|
|
|
def bucket_label(at)
|
|
range[:grain] == :day ? at.strftime("%d/%m") : at.strftime("%H:%M")
|
|
end
|
|
|
|
def sent_since(window)
|
|
recipients.sent.where(sent_at: (@now - window)..@now).count
|
|
end
|
|
|
|
def recipients
|
|
MailingRecipient.joins(:mailing).merge(Mailing.for_project(@project))
|
|
end
|
|
end
|