Browse Source

Handle polling via a GenServer that publishes on a PubSub

theenglishway (time) 4 years ago
parent
commit
e8e84a6682
3 changed files with 44 additions and 3 deletions
  1. 1 0
      lib/vaccins/application.ex
  2. 36 0
      lib/vaccins/poller.ex
  3. 7 3
      lib/vaccins_web/live/index.ex

+ 1 - 0
lib/vaccins/application.ex

@@ -14,6 +14,7 @@ defmodule Vaccins.Application do
       # Start the Endpoint (http/https)
       VaccinsWeb.Endpoint,
       Vaccins.LocationStore,
+      Vaccins.Poller,
       {Finch, name: Vaccins.Finch}
     ]
 

+ 36 - 0
lib/vaccins/poller.ex

@@ -0,0 +1,36 @@
+defmodule Vaccins.Poller do
+  use GenServer
+  alias Vaccins.{LocationStore, Search}
+  @name Vaccins.Poller
+  @refresh_period_ms 5 * 1000
+
+  def start_link(opts), do: GenServer.start_link(__MODULE__, opts, name: @name)
+
+  @impl true
+  def init(_opts) do
+    trigger_periodic_refresh()
+    {:ok, %{locations: LocationStore.get_locations()}}
+  end
+
+  @impl true
+  def handle_info(:periodic_refresh, state = %{locations: locations}) do
+    locations |> Enum.each(&Search.async_trigger_query/1)
+    trigger_periodic_refresh()
+    {:noreply, state}
+  end
+
+  @impl true
+  def handle_info({:query_result, id, res}, state = %{locations: locations}) do
+    {:noreply, state}
+  end
+
+  @impl true
+  def handle_info({:location_availabilities, id, res}, state = %{locations: locations}) do
+    Phoenix.PubSub.broadcast(Vaccins.PubSub, "locations", {:new_availabilities, id, res})
+    {:noreply, state}
+  end
+
+  defp trigger_periodic_refresh() do
+    Process.send_after(self(), :periodic_refresh, @refresh_period_ms)
+  end
+end

+ 7 - 3
lib/vaccins_web/live/index.ex

@@ -7,6 +7,7 @@ defmodule VaccinsWeb.IndexLive do
   @impl true
   def mount(_params, %{"is_local?" => is_local?}, socket) do
     locations = LocationStore.get_locations()
+    Phoenix.PubSub.subscribe(Vaccins.PubSub, "locations")
 
     {:ok,
      socket
@@ -20,9 +21,7 @@ defmodule VaccinsWeb.IndexLive do
        location_cs: LocationStore.LocationRaw.changeset(%{}),
        display_cs: false
      )
-     |> set_title()
-     |> trigger_global_refresh
-     |> trigger_periodic_refresh}
+     |> set_title()}
   end
 
   defp set_title(socket = %{assigns: %{locations_with_early_slots: early}}) do
@@ -113,6 +112,11 @@ defmodule VaccinsWeb.IndexLive do
     {:noreply, socket}
   end
 
+  def handle_info({:new_availabilities, id, res}, socket = %{assigns: %{locations: valid}}) do
+    send_update(VaccinsWeb.LocationComponent, id: id, availabilities: res)
+    {:noreply, socket}
+  end
+
   defp trigger_global_refresh(socket = %{assigns: %{locations: locations}}) do
     locations
     |> Enum.each(&send_update(VaccinsWeb.LocationComponent, id: &1.id, force_refresh: true))