-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
perf(ScheduleController): Fetch schedules by individual stop for more cache hits #231
Merged
Merged
Changes from 14 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
2cd5a37
perf(ScheduleController): Fetch schedules by individual stop for more…
KaylaBrady f1cb85e
perf(MBTAV3API.Repository): Cache schedules responses for 1 hour
KaylaBrady fa81ced
feat(locustfile): Represent global data caching
KaylaBrady 35a8a64
feat(load_testing): more realistic stop distribution
KaylaBrady 711d8cc
fix(RepositoryCache): Actually start the cache
KaylaBrady 3d7349a
style(locustfile): run linting
KaylaBrady 3cb153f
perf(Repository): Try TTL cache for all static GTFS requests
KaylaBrady 8493926
fix(RepositoryTest): clear cache
KaylaBrady 9ec572e
fix(Locustfile): More realistic nearby stops numbers
KaylaBrady 7015907
perf(ScheduleController): Don't use task when only one stop
KaylaBrady 43f4bb9
perf(ScheduleController): Only make requests async when more than 1
KaylaBrady b487e91
test(Repository): Test schedules actually cached
KaylaBrady 7245675
cleanup(locustfile): stray prints
KaylaBrady 62b59fe
revert locustfile changes for separate PR
KaylaBrady 83e238b
refactor(Repository): Cache all/3, remove unused alerts fn
KaylaBrady 25330fd
feat(ScheduleController): unordered tasks & unsorted schedule list
KaylaBrady aef24c8
style: fix formatting
KaylaBrady f6c9331
fix(ScheduleControllerTest): Remove sorting expectation
KaylaBrady a8be11f
Merge branch 'main' into kb-cacheable-scheds
KaylaBrady File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,24 +67,34 @@ end | |
|
||
defmodule MBTAV3API.Repository.Impl do | ||
@behaviour MBTAV3API.Repository | ||
|
||
use Nebulex.Caching.Decorators | ||
|
||
alias MBTAV3API.JsonApi | ||
|
||
@ttl :timer.hours(1) | ||
|
||
@impl true | ||
def alerts(params, opts \\ []), do: all(MBTAV3API.Alert, params, opts) | ||
|
||
@impl true | ||
@decorate cacheable(cache: MBTAV3API.RepositoryCache, on_error: :nothing, opts: [ttl: @ttl]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pulled from dotcom |
||
def route_patterns(params, opts \\ []), do: all(MBTAV3API.RoutePattern, params, opts) | ||
|
||
@impl true | ||
@decorate cacheable(cache: MBTAV3API.RepositoryCache, on_error: :nothing, opts: [ttl: @ttl]) | ||
def routes(params, opts \\ []), do: all(MBTAV3API.Route, params, opts) | ||
|
||
@impl true | ||
@decorate cacheable(cache: MBTAV3API.RepositoryCache, on_error: :nothing, opts: [ttl: @ttl]) | ||
def schedules(params, opts \\ []), do: all(MBTAV3API.Schedule, params, opts) | ||
|
||
@impl true | ||
@decorate cacheable(cache: MBTAV3API.RepositoryCache, on_error: :nothing, opts: [ttl: @ttl]) | ||
def stops(params, opts \\ []), do: all(MBTAV3API.Stop, params, opts) | ||
|
||
@impl true | ||
@decorate cacheable(cache: MBTAV3API.RepositoryCache, on_error: :nothing, opts: [ttl: @ttl]) | ||
def trips(params, opts \\ []), do: all(MBTAV3API.Trip, params, opts) | ||
|
||
@spec all(module(), JsonApi.Params.t(), Keyword.t()) :: | ||
boringcactus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
defmodule MBTAV3API.RepositoryCache do | ||
@moduledoc """ | ||
Cache used to reduce the number of calls to the V3 API. | ||
""" | ||
use Nebulex.Cache, otp_app: :mobile_app_backend, adapter: Nebulex.Adapters.Local | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,34 @@ | ||
defmodule MobileAppBackendWeb.ScheduleController do | ||
use MobileAppBackendWeb, :controller | ||
require Logger | ||
alias MBTAV3API.JsonApi | ||
alias MBTAV3API.Repository | ||
|
||
def schedules(conn, %{"stop_ids" => stop_ids, "date_time" => date_time}) do | ||
if stop_ids == "" do | ||
def schedules(conn, %{"stop_ids" => stop_ids_concat, "date_time" => date_time}) do | ||
if stop_ids_concat == "" do | ||
json(conn, %{schedules: [], trips: %{}}) | ||
else | ||
{:ok, data} = | ||
get_filter(stop_ids, date_time) | ||
|> fetch_schedules() | ||
stop_ids = String.split(stop_ids_concat, ",") | ||
|
||
json(conn, data) | ||
service_date = parse_service_date(date_time) | ||
|
||
filters = Enum.map(stop_ids, &get_filter(&1, service_date)) | ||
|
||
data = | ||
case filters do | ||
[filter] -> fetch_schedules(filter) | ||
filters -> fetch_schedules_parallel(filters) | ||
end | ||
|
||
case data do | ||
:error -> | ||
conn | ||
|> put_status(:internal_server_error) | ||
|> json(%{error: "fetch_failed"}) | ||
|
||
data -> | ||
json(conn, data) | ||
end | ||
end | ||
end | ||
|
||
|
@@ -39,20 +56,50 @@ defmodule MobileAppBackendWeb.ScheduleController do | |
json(conn, response) | ||
end | ||
|
||
@spec get_filter(String.t(), String.t()) :: [JsonApi.Params.filter_param()] | ||
defp get_filter(stop_ids, date_time) do | ||
date_time = Util.parse_datetime!(date_time) | ||
service_date = Util.datetime_to_gtfs(date_time) | ||
[stop: stop_ids, date: service_date] | ||
@spec parse_service_date(String.t()) :: Date.t() | ||
defp parse_service_date(date_string) do | ||
date_string | ||
|> Util.parse_datetime!() | ||
|> Util.datetime_to_gtfs() | ||
end | ||
|
||
@spec get_filter(String.t(), Date.t()) :: [JsonApi.Params.filter_param()] | ||
defp get_filter(stop_id, service_date) do | ||
[stop: stop_id, date: service_date] | ||
end | ||
|
||
@spec fetch_schedules_parallel([[JsonApi.Params.filter_param()]]) :: | ||
%{schedules: [MBTAV3API.Schedule.t()], trips: JsonApi.Object.trip_map()} | :error | ||
defp fetch_schedules_parallel(filters) do | ||
filters | ||
|> Task.async_stream(fn filter_params -> | ||
{filter_params, fetch_schedules(filter_params)} | ||
end) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to call this with |
||
|> Enum.reduce_while(%{schedules: [], trips: %{}}, fn result, acc -> | ||
case result do | ||
{:ok, {_params, %{schedules: schedules, trips: trips}}} -> | ||
{:cont, %{schedules: acc.schedules ++ schedules, trips: Map.merge(acc.trips, trips)}} | ||
boringcactus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
{_result_type, {params, _response}} -> | ||
Logger.warning( | ||
"#{__MODULE__} skipped returning schedules due to error. params=#{inspect(params)}" | ||
) | ||
|
||
{:halt, :error} | ||
end | ||
end) | ||
end | ||
|
||
@spec fetch_schedules([JsonApi.Params.filter_param()]) :: | ||
{:ok, %{schedules: [MBTAV3API.Schedule.t()], trips: JsonApi.Object.trip_map()}} | ||
| {:error, term()} | ||
%{schedules: [MBTAV3API.Schedule.t()], trips: JsonApi.Object.trip_map()} | ||
| :error | ||
defp fetch_schedules(filter) do | ||
with {:ok, %{data: schedules, included: %{trips: trips}}} <- | ||
Repository.schedules(filter: filter, include: :trip, sort: {:departure_time, :asc}) do | ||
{:ok, %{schedules: schedules, trips: trips}} | ||
case Repository.schedules(filter: filter, include: :trip, sort: {:departure_time, :asc}) do | ||
{:ok, %{data: schedules, included: %{trips: trips}}} -> | ||
%{schedules: schedules, trips: trips} | ||
|
||
_ -> | ||
:error | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting to 2 hours based on the recommendation here that ttl should be less than gc_interval