analytics/lib/workers/schedule_email_reports.ex
Uku Taht 80b98762f4
More robust scheduling for email reports (#189)
* More robust scheduling for email reports

* Update config for new email report jobs

* Only build docker on master

* Use Postgres 12 in travis

* Cache elixir files

* use Postgres 12 in travis

* Specify env on one line

* Wrong postgres version
2020-06-28 13:24:54 +03:00

87 lines
2.4 KiB
Elixir

defmodule Plausible.Workers.ScheduleEmailReports do
use Plausible.Repo
use Oban.Worker, queue: :schedule_email_reports
alias Plausible.Workers.SendEmailReport
require Logger
@impl Oban.Worker
@doc """
Email reports should be sent on Monday at 9am according to the timezone
of a site. This job runs every day at midnight to ensure that all sites
have a scheduled job for email reports.
"""
def perform(_args, _job) do
schedule_weekly_emails()
schedule_monthly_emails()
end
defp schedule_weekly_emails() do
weekly_jobs = from(
j in Oban.Job,
where: j.worker == "Plausible.Workers.SendEmailReport"
and fragment("(? ->> 'interval')", j.args) == "weekly"
)
sites =
Repo.all(
from s in Plausible.Site,
join: wr in Plausible.Site.WeeklyReport,
on: wr.site_id == s.id,
left_join: job in subquery(weekly_jobs),
on: fragment("(? -> 'site_id')::int", job.args) == s.id and
job.state not in ["completed", "discarded"],
where: is_nil(job),
preload: [weekly_report: wr]
)
for site <- sites do
SendEmailReport.new(%{site_id: site.id, interval: "weekly"}, scheduled_at: monday_9am(site.timezone))
|> Oban.insert!()
end
:ok
end
def monday_9am(timezone) do
Timex.now(timezone)
|> Timex.shift(weeks: 1)
|> Timex.beginning_of_week()
|> Timex.shift(hours: 9)
end
defp schedule_monthly_emails() do
monthly_jobs = from(
j in Oban.Job,
where: j.worker == "Plausible.Workers.SendEmailReport"
and fragment("(? ->> 'interval')", j.args) == "monthly"
)
sites =
Repo.all(
from s in Plausible.Site,
join: mr in Plausible.Site.MonthlyReport,
on: mr.site_id == s.id,
left_join: job in subquery(monthly_jobs),
on:
fragment("(? -> 'site_id')::int", job.args) == s.id and
job.state not in ["completed", "discarded"],
where: is_nil(job),
preload: [monthly_report: mr]
)
for site <- sites do
SendEmailReport.new(%{site_id: site.id, interval: "monthly"}, scheduled_at: first_of_month_9am(site.timezone))
|> Oban.insert!()
end
:ok
end
def first_of_month_9am(timezone) do
Timex.now(timezone)
|> Timex.shift(months: 1)
|> Timex.beginning_of_month()
|> Timex.shift(hours: 9)
end
end