From f3582f662883c575132043650714ccc085b2d1f2 Mon Sep 17 00:00:00 2001 From: sloane Date: Fri, 16 Aug 2024 10:51:02 -0400 Subject: [PATCH 1/2] feat: cache routes --- lib/screens/application.ex | 3 ++- lib/screens/routes/routes_cache.ex | 34 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 lib/screens/routes/routes_cache.ex diff --git a/lib/screens/application.ex b/lib/screens/application.ex index 3630957d9..2fdf4841b 100644 --- a/lib/screens/application.ex +++ b/lib/screens/application.ex @@ -38,7 +38,8 @@ defmodule Screens.Application do {Screens.OlCrowding.Agent, %{}}, {Screens.ScreenApiResponseCache, []}, Screens.Streams.Alerts, - Screens.Stops.StopsToRoutes + Screens.Stops.StopsToRoutes, + Screens.Routes.RoutesCache ] # See https://hexdocs.pm/elixir/Supervisor.html diff --git a/lib/screens/routes/routes_cache.ex b/lib/screens/routes/routes_cache.ex new file mode 100644 index 000000000..b13320a01 --- /dev/null +++ b/lib/screens/routes/routes_cache.ex @@ -0,0 +1,34 @@ +defmodule Screens.Routes.RoutesCache do + @moduledoc """ + A read-through cache of routes by ID. + """ + use Nebulex.Cache, + otp_app: :screens, + adapter: Nebulex.Adapters.Local + + alias Screens.Routes.Route + + @base_ttl :timer.hours(1) + + @spec by_id(id :: String.t()) :: Route.t() | nil + def by_id(id) do + if route = get(id) do + route + else + case Route.by_id(id) do + {:ok, %Route{} = route} -> + put(id, route, ttl: ttl()) + + route + + _ -> + nil + end + end + end + + def ttl do + additional_minutes = :rand.uniform(30) + @base_ttl + :timer.minutes(additional_minutes) + end +end From bf97753ba16875fb8107dfbab3be5f57d50d36c6 Mon Sep 17 00:00:00 2001 From: sloane Date: Fri, 16 Aug 2024 10:57:50 -0400 Subject: [PATCH 2/2] feat: use route cache in alerts filter expansion --- config/config.exs | 1 + config/test.exs | 3 ++- lib/screens/alerts/cache/filter.ex | 7 +++---- lib/screens/routes/routes_cache.ex | 21 +++++++++++++-------- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/config/config.exs b/config/config.exs index 762e36f1f..080d2aa16 100644 --- a/config/config.exs +++ b/config/config.exs @@ -486,6 +486,7 @@ config :screens, Screens.ScreenApiResponseCache, allocated_memory: 250_000_000 config :screens, Screens.Stops.StopsToRoutes, adapter: Nebulex.Adapters.Local +config :screens, Screens.Routes.RoutesCache, adapter: Nebulex.Adapters.Local # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. diff --git a/config/test.exs b/config/test.exs index 31ccf79b9..01855c5c4 100644 --- a/config/test.exs +++ b/config/test.exs @@ -27,7 +27,7 @@ config :screens, blue_bikes_station_status_url: [:no_api_requests_allowed_during_testing], blue_bikes_api_client: Screens.BlueBikes.FakeClient, stops_to_routes_route_mod: Screens.Routes.Route.Mock, - alerts_cache_filter_route_mod: Screens.Routes.Route.Mock, + routes_cache_route_mod: Screens.Routes.Route.Mock, dup_headsign_replacements: %{ "Test 1" => "T1" }, @@ -164,3 +164,4 @@ config :screens, :screens_by_alert, screens_ttl_seconds: 1 config :screens, Screens.Stops.StopsToRoutes, adapter: Nebulex.Adapters.Nil +config :screens, Screens.Routes.RoutesCache, adapter: Nebulex.Adapters.Nil diff --git a/lib/screens/alerts/cache/filter.ex b/lib/screens/alerts/cache/filter.ex index 40ee875aa..e496bab78 100644 --- a/lib/screens/alerts/cache/filter.ex +++ b/lib/screens/alerts/cache/filter.ex @@ -3,11 +3,10 @@ defmodule Screens.Alerts.Cache.Filter do Logic to apply filters to a list of `Screens.Alerts.Alert` structs. """ alias Screens.Routes.Route + alias Screens.Routes.RoutesCache alias Screens.RouteType alias Screens.Stops.StopsToRoutes - @route_mod Application.compile_env(:screens, :alerts_cache_filter_route_mod, Route) - @default_activities ~w[BOARD EXIT RIDE] @type filter_opts() :: %{ @@ -127,8 +126,8 @@ defmodule Screens.Alerts.Cache.Filter do end defp matchers_for_route_id(route_id) do - case @route_mod.by_id(route_id) do - {:ok, %Route{type: type}} -> + case RoutesCache.by_id(route_id) do + %Route{type: type} -> [ %{ route_type: RouteType.to_id(type), diff --git a/lib/screens/routes/routes_cache.ex b/lib/screens/routes/routes_cache.ex index b13320a01..0222319b9 100644 --- a/lib/screens/routes/routes_cache.ex +++ b/lib/screens/routes/routes_cache.ex @@ -4,10 +4,12 @@ defmodule Screens.Routes.RoutesCache do """ use Nebulex.Cache, otp_app: :screens, - adapter: Nebulex.Adapters.Local + adapter: Application.compile_env(:screens, [__MODULE__, :adapter]) alias Screens.Routes.Route + @route_mod Application.compile_env(:screens, :routes_cache_route_mod, Screens.Routes.Route) + @base_ttl :timer.hours(1) @spec by_id(id :: String.t()) :: Route.t() | nil @@ -15,15 +17,18 @@ defmodule Screens.Routes.RoutesCache do if route = get(id) do route else - case Route.by_id(id) do - {:ok, %Route{} = route} -> - put(id, route, ttl: ttl()) + route = fetch_by_id(id) + + unless is_nil(route), do: put(id, route, ttl: ttl()) - route + route + end + end - _ -> - nil - end + defp fetch_by_id(id) do + case @route_mod.by_id(id) do + {:ok, %Route{} = route} -> route + _ -> nil end end