Skip to content

Commit

Permalink
try simply removing the cache
Browse files Browse the repository at this point in the history
  • Loading branch information
anthonyshull committed Apr 9, 2024
1 parent 9c6de44 commit 5a06a3b
Show file tree
Hide file tree
Showing 6 changed files with 5 additions and 178 deletions.
2 changes: 1 addition & 1 deletion deploy/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ services:
test: curl --fail http://localhost:4002/_health || exit 1
interval: 10s
retries: 5
start_period: 60s
start_period: 180s
timeout: 10s
volumes:
- ../:/app
Expand Down
3 changes: 1 addition & 2 deletions lib/dotcom/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ defmodule Dotcom.Application do

children =
[
{Application.get_env(:dotcom, :cache, Dotcom.Cache.Multilevel), []},
MBTA.Cache
{Application.get_env(:dotcom, :cache, Dotcom.Cache.Multilevel), []}
] ++
if Application.get_env(:dotcom, :env) != :test do
[
Expand Down
3 changes: 1 addition & 2 deletions lib/mbta/api.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ defmodule MBTA.Api do

use HTTPoison.Base

alias MBTA.{Cache, SentryExtra}
alias MBTA.SentryExtra
alias Util

@behaviour MBTA.Api.Behaviour
Expand All @@ -29,7 +29,6 @@ defmodule MBTA.Api do
with {time, response} <- timed_get(url, params, opts),
:ok <- log_response(url, params, time, response),
{:ok, http_response} <- response,
{:ok, http_response} <- Cache.cache_response(url, params, http_response),
{:ok, body} <- body(http_response) do
body
|> JsonApi.parse()
Expand Down
145 changes: 0 additions & 145 deletions lib/mbta/cache.ex
Original file line number Diff line number Diff line change
@@ -1,147 +1,2 @@
defmodule MBTA.Cache do
@moduledoc """
Cache HTTP responses from MBTA.
Static data such as schedules and stops do not change frequently. However,
we do want to check in with the API periodically to make sure we have the
most recent data. This module stores the previous HTTP responses, and can
return them if the server says that the data is unchanged.
"""

require Logger

use GenServer

alias HTTPoison.Response

@type url :: String.t()
@type params :: Enumerable.t()

def start_link(opts \\ []) do
opts = Keyword.put_new(opts, :name, __MODULE__)
GenServer.start_link(__MODULE__, opts, opts)
end

@doc """
Given a URL, parameters, and an HTTP response:
- If the HTTP response is a 304 Not Modified, return the previously cached response
- If the HTTP response is a 200, 400, or 404, cache it and return the response
- If the HTTP response is anything else, try to return a cached response, otherwise return the response as-is
"""
@spec cache_response(url, params, Response.t()) ::
{:ok, Response.t()} | {:error, :no_cached_response}
def cache_response(name \\ __MODULE__, url, params, response)

def cache_response(name, url, params, %{status_code: 304}) do
lookup_cached_response(name, url, params)
rescue
ArgumentError ->
{:error, :no_cached_response}
end

def cache_response(name, url, params, %{status_code: status_code} = response)
when status_code in [200, 400, 404] do
key = {url, params}
last_modified = header(response, "last-modified")
true = :ets.insert(name, {key, last_modified, response, now()})
{:ok, response}
end

def cache_response(name, url, params, response) do
lookup_cached_response(name, url, params)
rescue
ArgumentError ->
{:ok, response}
end

defp lookup_cached_response(name, url, params) do
key = {url, params}
element = :ets.lookup_element(name, key, 3)
:ets.update_element(name, key, {4, now()})
{:ok, element}
end

@doc """
Return a list of cache headers for the given URL/parameters.
"""
@spec cache_headers(url, params) :: [{String.t(), String.t()}]
def cache_headers(name \\ __MODULE__, url, params) do
last_modfied = :ets.lookup_element(name, {url, params}, 2)
[{"if-modified-since", last_modfied}]
rescue
ArgumentError ->
[]
end

defp header(%{headers: headers}, header) do
case Enum.find(headers, &(String.downcase(elem(&1, 0)) == header)) do
{_, value} -> value
nil -> nil
end
end

@doc "Expire the least-recently-used cache items"
@spec expire!() :: :ok
def expire!(name \\ __MODULE__) do
GenServer.call(name, :expire!)
end

@impl GenServer
def init(opts) do
name = Keyword.fetch!(opts, :name)

^name =
:ets.new(name, [
:set,
:named_table,
:public,
{:read_concurrency, true},
{:write_concurrency, true}
])

timeout = Keyword.get(opts, :timeout, 60_000)
Process.send_after(self(), :expire, timeout)
size = Keyword.get(opts, :size, Application.get_env(:dotcom, :v3_api_cache_size))
{:ok, %{name: name, size: size, timeout: timeout}}
end

@impl GenServer
def handle_call(:expire!, _from, state) do
:ok = do_expire(state)
{:reply, :ok, state}
end

@impl GenServer
def handle_info(:expire, state) do
:ok = do_expire(state)
Process.send_after(self(), :expire, state.timeout)
{:noreply, state}
end

defp do_expire(%{name: name, size: size}) do
current_size = :ets.info(name, :size)

_ =
Logger.info(fn ->
"#{name} report - size=#{current_size} max_size=#{size} memory=#{:ets.info(name, :memory)}"
end)

if current_size > size do
# keep half of the cache, so that we don't bounce around clearing the
# cache each minute
keep = div(size, 2)

name
|> :ets.match({:"$2", :_, :_, :"$1"})
|> Enum.sort(&>=/2)
|> Enum.drop(keep)
|> Enum.each(fn [_lru, key] -> :ets.delete(name, key) end)
else
:ok
end
end

defp now do
System.monotonic_time()
end
end
28 changes: 1 addition & 27 deletions lib/mbta/headers.ex
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
defmodule MBTA.Headers do
@moduledoc """
Builds headers for calling the MBTA.Api.
Setting `:use_cache?` to `true` will include headers set by MBTA.Cache.cache_headers.
If `:use_cache?` is set to `true`, you must also include a `:url` and a `:params` option.
"""

alias MBTA.Cache

@type header_list :: [{String.t(), String.t()}]

@spec build(String.t() | nil, Keyword.t()) :: header_list
def build(api_key, opts) do
def build(api_key, _opts) do
[]
|> api_key_header(api_key)
|> proxy_headers()
|> cache_headers(opts)
|> extra_headers()
end

Expand Down Expand Up @@ -44,26 +38,6 @@ defmodule MBTA.Headers do
headers
end

@spec cache_headers(header_list, Keyword.t()) :: header_list
defp cache_headers(headers, opts) do
if Keyword.get(opts, :use_cache?, true) do
do_cache_headers(headers, opts)
else
headers
end
end

@spec do_cache_headers(header_list, Keyword.t()) :: header_list
defp do_cache_headers(headers, opts) do
params = Keyword.fetch!(opts, :params)
cache_headers_fn = Keyword.get(opts, :cache_headers_fn, &Cache.cache_headers/2)

opts
|> Keyword.fetch!(:url)
|> cache_headers_fn.(params)
|> Enum.reduce(headers, &[&1 | &2])
end

@spec extra_headers(header_list) :: header_list
defp extra_headers(headers) do
Util.config(:dotcom, :enable_experimental_features)
Expand Down
2 changes: 1 addition & 1 deletion playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module.exports = defineConfig({
userAgent: 'Playwright',
},
/* set the expect timeout to 10s */
expect: { timeout: 10000 },
expect: { timeout: 30000 },
/* Configure projects for major browsers */
projects: [
{
Expand Down

0 comments on commit 5a06a3b

Please sign in to comment.