analytics/lib/workers/spike_notifier.ex
Karl-Aksel Puulmann f3509f2a17
Refactor spike detection top sources query (#3770)
* ORDER BY referrer_source for spikes job

This is more consistent with the rest of the queries

* Refactor top_sources -> top_sources_for_spike

* Remove more dead code

* Remove unused arguments

* Remove unused select arguments

* Add a test to top_sources_for_spike
2024-02-13 08:28:32 +02:00

64 lines
1.8 KiB
Elixir

defmodule Plausible.Workers.SpikeNotifier do
use Plausible.Repo
alias Plausible.Stats.Query
alias Plausible.Site.SpikeNotification
use Oban.Worker, queue: :spike_notifications
@at_most_every "12 hours"
@impl Oban.Worker
def perform(_job, clickhouse \\ Plausible.Stats.Clickhouse) do
notifications =
Repo.all(
from sn in SpikeNotification,
where: is_nil(sn.last_sent),
or_where: sn.last_sent < fragment("now() - INTERVAL ?", @at_most_every),
join: s in Plausible.Site,
on: sn.site_id == s.id,
where: not s.locked,
preload: [site: s]
)
for notification <- notifications do
query = Query.from(notification.site, %{"period" => "realtime"})
current_visitors = clickhouse.current_visitors(notification.site, query)
if current_visitors >= notification.threshold do
sources = clickhouse.top_sources_for_spike(notification.site, query, 3, 1)
notify(notification, current_visitors, sources)
end
end
:ok
end
defp notify(notification, current_visitors, sources) do
for recipient <- notification.recipients do
send_notification(recipient, notification.site, current_visitors, sources)
end
notification
|> SpikeNotification.was_sent()
|> Repo.update()
end
defp send_notification(recipient, site, current_visitors, sources) do
site = Repo.preload(site, :members)
dashboard_link =
if Enum.any?(site.members, &(&1.email == recipient)) do
PlausibleWeb.Endpoint.url() <> "/" <> URI.encode_www_form(site.domain)
end
template =
PlausibleWeb.Email.spike_notification(
recipient,
site,
current_visitors,
sources,
dashboard_link
)
Plausible.Mailer.send(template)
end
end