FEATURE: if site is under extreme load show anon view

If a particular path is being hit extremely hard by logged on users,
revert to anonymous cached view.

This will only come into effect if 3 requests queue for longer than 2 seconds
on a *single* path.

This can happen if a URL is shared with the entire forum base and everyone
is logged on
This commit is contained in:
Sam
2018-04-18 16:58:40 +10:00
parent 7bf9650e96
commit 59cd7894d9
6 changed files with 125 additions and 10 deletions

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require_dependency "mobile_detection"
require_dependency "crawler_detection"
require_dependency "guardian"
@ -10,9 +12,9 @@ module Middleware
end
class Helper
USER_AGENT = "HTTP_USER_AGENT".freeze
RACK_SESSION = "rack.session".freeze
ACCEPT_ENCODING = "HTTP_ACCEPT_ENCODING".freeze
USER_AGENT = "HTTP_USER_AGENT"
RACK_SESSION = "rack.session"
ACCEPT_ENCODING = "HTTP_ACCEPT_ENCODING"
def initialize(env)
@env = env
@ -86,7 +88,40 @@ module Middleware
def no_cache_bypass
request = Rack::Request.new(@env)
request.cookies['_bypass_cache'].nil?
request.cookies['_bypass_cache'].nil? &&
request[Auth::DefaultCurrentUserProvider::API_KEY].nil? &&
@env[Auth::DefaultCurrentUserProvider::USER_API_KEY].nil?
end
def force_anonymous!
@env[Auth::DefaultCurrentUserProvider::USER_API_KEY] = nil
@env['HTTP_COOKIE'] = nil
@env['rack.request.cookie.hash'] = {}
@env['rack.request.cookie.string'] = ''
@env['_bypass_cache'] = nil
request = Rack::Request.new(@env)
request.delete_param('api_username')
request.delete_param('api_key')
end
def check_logged_in_rate_limit!
limiter = RateLimiter.new(
nil,
"logged_in_anon_cache_#{@env["HOST"]}/#{@env["REQUEST_URI"]}",
GlobalSetting.force_anonymous_min_per_10_seconds,
10
)
!limiter.performed!(raise_error: false)
end
def should_force_anonymous?
if queue_time = @env['REQUEST_QUEUE_SECONDS']
if queue_time > GlobalSetting.force_anonymous_min_queue_seconds && get?
return check_logged_in_rate_limit!
end
end
false
end
def cacheable?
@ -142,13 +177,26 @@ module Middleware
def call(env)
helper = Helper.new(env)
force_anon = false
if helper.cacheable?
helper.cached || helper.cache(@app.call(env))
else
@app.call(env)
if helper.should_force_anonymous?
force_anon = env["DISCOURSE_FORCE_ANON"] = true
helper.force_anonymous!
end
result =
if helper.cacheable?
helper.cached || helper.cache(@app.call(env))
else
@app.call(env)
end
if force_anon
result[1]["Set-Cookie"] = "dosp=1"
end
result
end
end