autocomplete: rework cache policy.

The previous cache policy was that all autocomplete results were cached
for a fixed 7 days. The new policy is that if autocomplete returns more
than 10 results they're cached for 24 hours, otherwise if it returns
less than 10 results they're cached for 1 hour.

The rationale is that if autocomplete returns a lot of results, then the
top 10 results are relatively stable and unlikely to change, but if it
returns less than 10 results, then the results are unstable and can be
easily changed.

We also change it so that autocomplete calls can be cached publicly.
Public caching means that HTTP requests are cached by Cloudflare. This
will ideally reduce load on the server and reduce latency for end users.
This is only safe for calls that return the same results for all users
(i.e. the results don't depend on the current user), since the cache is
publicly shared by all users. Currently username, favgroup, and saved
search autocomplete results depend on the current user, so they can't be
publicly cached.
This commit is contained in:
evazion
2020-12-13 00:45:22 -06:00
parent b0be8ae456
commit d6a5b9e252
2 changed files with 31 additions and 0 deletions

View File

@@ -8,6 +8,10 @@ class AutocompleteController < ApplicationController
@autocomplete = AutocompleteService.new(@query, @type, current_user: CurrentUser.user, limit: @limit)
@results = @autocomplete.autocomplete_results
@expires_in = @autocomplete.cache_duration
@public = @autocomplete.cache_publicly?
expires_in @expires_in, public: @public unless response.cache_control.present?
respond_with(@results)
end
end

View File

@@ -1,4 +1,6 @@
class AutocompleteService
extend Memoist
POST_STATUSES = %w[active deleted pending flagged appealed banned modqueue unmoderated]
STATIC_METATAGS = {
@@ -197,4 +199,29 @@ class AutocompleteService
results = autocomplete_tag(string).map { |result| result[:value] }
[query, results]
end
def cache_duration
if autocomplete_results.size == limit
24.hours
else
1.hour
end
end
# Queries that don't depend on the current user are safe to cache publicly.
def cache_publicly?
if type == :tag_query && parsed_search&.type == :tag
true
elsif type.in?(%i[tag artist wiki_page pool opensearch])
true
else
false
end
end
def parsed_search
PostQueryBuilder.new(query).terms.first
end
memoize :autocomplete_results
end