mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 20:18:00 +01:00
stop spawning off for advert updates
This commit is contained in:
parent
dd7aca809a
commit
cc4103fcea
5 changed files with 100 additions and 28 deletions
|
@ -19,7 +19,6 @@ defmodule Philomena.Adverts do
|
||||||
|> order_by(asc: fragment("random()"))
|
|> order_by(asc: fragment("random()"))
|
||||||
|> limit(1)
|
|> limit(1)
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
|> record_impression()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def random_live_for(image) do
|
def random_live_for(image) do
|
||||||
|
@ -33,25 +32,6 @@ defmodule Philomena.Adverts do
|
||||||
|> order_by(asc: fragment("random()"))
|
|> order_by(asc: fragment("random()"))
|
||||||
|> limit(1)
|
|> limit(1)
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
|> record_impression()
|
|
||||||
end
|
|
||||||
|
|
||||||
def click(%Advert{} = advert) do
|
|
||||||
spawn(fn ->
|
|
||||||
query = where(Advert, id: ^advert.id)
|
|
||||||
Repo.update_all(query, inc: [clicks: 1])
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp record_impression(nil), do: nil
|
|
||||||
|
|
||||||
defp record_impression(advert) do
|
|
||||||
spawn(fn ->
|
|
||||||
query = where(Advert, id: ^advert.id)
|
|
||||||
Repo.update_all(query, inc: [impressions: 1])
|
|
||||||
end)
|
|
||||||
|
|
||||||
advert
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp sfw?(image) do
|
defp sfw?(image) do
|
||||||
|
|
|
@ -17,6 +17,9 @@ defmodule Philomena.Application do
|
||||||
# Start the Ecto repository
|
# Start the Ecto repository
|
||||||
Philomena.Repo,
|
Philomena.Repo,
|
||||||
|
|
||||||
|
# Background queueing system
|
||||||
|
Philomena.ExqSupervisor,
|
||||||
|
|
||||||
# Starts a worker by calling: Philomena.Worker.start_link(arg)
|
# Starts a worker by calling: Philomena.Worker.start_link(arg)
|
||||||
# {Philomena.Worker, arg},
|
# {Philomena.Worker, arg},
|
||||||
Philomena.Servers.ImageProcessor,
|
Philomena.Servers.ImageProcessor,
|
||||||
|
@ -28,6 +31,7 @@ defmodule Philomena.Application do
|
||||||
{Phoenix.PubSub, [name: Philomena.PubSub, adapter: Phoenix.PubSub.PG2]},
|
{Phoenix.PubSub, [name: Philomena.PubSub, adapter: Phoenix.PubSub.PG2]},
|
||||||
|
|
||||||
# Start the endpoint when the application starts
|
# Start the endpoint when the application starts
|
||||||
|
PhilomenaWeb.AdvertUpdater,
|
||||||
PhilomenaWeb.StatsUpdater,
|
PhilomenaWeb.StatsUpdater,
|
||||||
PhilomenaWeb.UserFingerprintUpdater,
|
PhilomenaWeb.UserFingerprintUpdater,
|
||||||
PhilomenaWeb.UserIpUpdater,
|
PhilomenaWeb.UserIpUpdater,
|
||||||
|
|
81
lib/philomena_web/advert_updater.ex
Normal file
81
lib/philomena_web/advert_updater.ex
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
defmodule PhilomenaWeb.AdvertUpdater do
|
||||||
|
alias Philomena.Adverts.Advert
|
||||||
|
alias Philomena.Repo
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
def child_spec([]) do
|
||||||
|
%{
|
||||||
|
id: PhilomenaWeb.AdvertUpdater,
|
||||||
|
start: {PhilomenaWeb.AdvertUpdater, :start_link, [[]]}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_link([]) do
|
||||||
|
{:ok, spawn_link(&init/0)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def cast(type, advert_id) when type in [:impression, :click] do
|
||||||
|
pid = Process.whereis(:advert_updater)
|
||||||
|
if pid, do: send(pid, {type, advert_id})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp init do
|
||||||
|
Process.register(self(), :advert_updater)
|
||||||
|
run()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp run do
|
||||||
|
# Read impression counts from mailbox
|
||||||
|
{impressions, clicks} = receive_all()
|
||||||
|
|
||||||
|
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
|
||||||
|
|
||||||
|
# Create insert statements for Ecto
|
||||||
|
impressions = Enum.map(impressions, &impressions_insert_all(&1, now))
|
||||||
|
clicks = Enum.map(clicks, &clicks_insert_all(&1, now))
|
||||||
|
|
||||||
|
# Merge into table
|
||||||
|
impressions_update = update(Advert, inc: [impressions: fragment("EXCLUDED.impressions")])
|
||||||
|
clicks_update = update(Advert, inc: [clicks: fragment("EXCLUDED.clicks")])
|
||||||
|
|
||||||
|
Repo.insert_all(Advert, impressions, on_conflict: impressions_update, conflict_target: [:id])
|
||||||
|
Repo.insert_all(Advert, clicks, on_conflict: clicks_update, conflict_target: [:id])
|
||||||
|
|
||||||
|
:timer.sleep(:timer.seconds(10))
|
||||||
|
|
||||||
|
run()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp receive_all(impressions \\ %{}, clicks \\ %{}) do
|
||||||
|
receive do
|
||||||
|
{:impression, advert_id} ->
|
||||||
|
impressions = Map.update(impressions, advert_id, 1, &(&1 + 1))
|
||||||
|
receive_all(impressions, clicks)
|
||||||
|
|
||||||
|
{:click, advert_id} ->
|
||||||
|
clicks = Map.update(clicks, advert_id, 1, &(&1 + 1))
|
||||||
|
receive_all(impressions, clicks)
|
||||||
|
after
|
||||||
|
0 ->
|
||||||
|
{impressions, clicks}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp impressions_insert_all({advert_id, impressions}, now) do
|
||||||
|
%{
|
||||||
|
id: advert_id,
|
||||||
|
impressions: impressions,
|
||||||
|
created_at: now,
|
||||||
|
updated_at: now
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp clicks_insert_all({advert_id, clicks}, now) do
|
||||||
|
%{
|
||||||
|
id: advert_id,
|
||||||
|
clicks: clicks,
|
||||||
|
created_at: now,
|
||||||
|
updated_at: now
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,7 +1,7 @@
|
||||||
defmodule PhilomenaWeb.AdvertController do
|
defmodule PhilomenaWeb.AdvertController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
alias Philomena.Adverts
|
alias PhilomenaWeb.AdvertUpdater
|
||||||
alias Philomena.Adverts.Advert
|
alias Philomena.Adverts.Advert
|
||||||
|
|
||||||
plug :load_resource, model: Advert
|
plug :load_resource, model: Advert
|
||||||
|
@ -9,9 +9,8 @@ defmodule PhilomenaWeb.AdvertController do
|
||||||
def show(conn, _params) do
|
def show(conn, _params) do
|
||||||
advert = conn.assigns.advert
|
advert = conn.assigns.advert
|
||||||
|
|
||||||
Adverts.click(advert)
|
AdvertUpdater.cast(:click, advert.id)
|
||||||
|
|
||||||
conn
|
redirect(conn, external: advert.link)
|
||||||
|> redirect(external: advert.link)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
defmodule PhilomenaWeb.AdvertPlug do
|
defmodule PhilomenaWeb.AdvertPlug do
|
||||||
|
alias PhilomenaWeb.AdvertUpdater
|
||||||
alias Philomena.Adverts
|
alias Philomena.Adverts
|
||||||
alias Plug.Conn
|
alias Plug.Conn
|
||||||
|
|
||||||
|
@ -9,15 +10,14 @@ defmodule PhilomenaWeb.AdvertPlug do
|
||||||
image = conn.assigns[:image]
|
image = conn.assigns[:image]
|
||||||
show_ads? = show_ads?(user)
|
show_ads? = show_ads?(user)
|
||||||
|
|
||||||
conn
|
maybe_assign_ad(conn, image, show_ads?)
|
||||||
|> maybe_assign_ad(image, show_ads?)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp maybe_assign_ad(conn, nil, true),
|
defp maybe_assign_ad(conn, nil, true),
|
||||||
do: Conn.assign(conn, :advert, Adverts.random_live())
|
do: Conn.assign(conn, :advert, record_impression(Adverts.random_live()))
|
||||||
|
|
||||||
defp maybe_assign_ad(conn, image, true),
|
defp maybe_assign_ad(conn, image, true),
|
||||||
do: Conn.assign(conn, :advert, Adverts.random_live_for(image))
|
do: Conn.assign(conn, :advert, record_impression(Adverts.random_live_for(image)))
|
||||||
|
|
||||||
defp maybe_assign_ad(conn, _image, _false),
|
defp maybe_assign_ad(conn, _image, _false),
|
||||||
do: conn
|
do: conn
|
||||||
|
@ -27,4 +27,12 @@ defmodule PhilomenaWeb.AdvertPlug do
|
||||||
|
|
||||||
defp show_ads?(_user),
|
defp show_ads?(_user),
|
||||||
do: true
|
do: true
|
||||||
|
|
||||||
|
defp record_impression(nil), do: nil
|
||||||
|
|
||||||
|
defp record_impression(advert) do
|
||||||
|
AdvertUpdater.cast(:impression, advert.id)
|
||||||
|
|
||||||
|
advert
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue