Class: Gitlab::Database::LoadBalancing::RackMiddleware
- Inherits:
-
Object
- Object
- Gitlab::Database::LoadBalancing::RackMiddleware
- Defined in:
- lib/gitlab/database/load_balancing/rack_middleware.rb
Overview
Rack middleware to handle sticking when serving Rails requests. Grape API calls are handled separately as different API endpoints need to stick based on different objects.
Constant Summary collapse
- STICK_OBJECT =
'load_balancing.stick_object'
Instance Method Summary collapse
- #call(env) ⇒ Object
- #clear ⇒ Object
-
#find_caught_up_replica(env) ⇒ Object
Determine if we need to stick based on currently available user data.
-
#initialize(app) ⇒ RackMiddleware
constructor
A new instance of RackMiddleware.
-
#stick_if_necessary(env) ⇒ Object
Determine if we need to stick after handling a request.
-
#sticking_namespaces(env) ⇒ Object
Determines the sticking namespace and identifier based on the Rack environment.
Constructor Details
#initialize(app) ⇒ RackMiddleware
Returns a new instance of RackMiddleware.
12 13 14 |
# File 'lib/gitlab/database/load_balancing/rack_middleware.rb', line 12 def initialize(app) @app = app end |
Instance Method Details
#call(env) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/gitlab/database/load_balancing/rack_middleware.rb', line 16 def call(env) # Ensure that any state that may have run before the first request # doesn't linger around. clear find_caught_up_replica(env) result = @app.call(env) ActiveSupport::Notifications.instrument('web_transaction_completed.load_balancing') stick_if_necessary(env) result ensure clear end |
#clear ⇒ Object
57 58 59 60 |
# File 'lib/gitlab/database/load_balancing/rack_middleware.rb', line 57 def clear ::Gitlab::Database::LoadBalancing.release_hosts ::Gitlab::Database::LoadBalancing::Session.clear_session end |
#find_caught_up_replica(env) ⇒ Object
Determine if we need to stick based on currently available user data.
Typically this code will only be reachable for Rails requests as Grape data is not yet available at this point.
38 39 40 41 42 43 44 |
# File 'lib/gitlab/database/load_balancing/rack_middleware.rb', line 38 def find_caught_up_replica(env) namespaces_and_ids = sticking_namespaces(env) namespaces_and_ids.each do |(sticking, namespace, id)| sticking.find_caught_up_replica(namespace, id) end end |
#stick_if_necessary(env) ⇒ Object
Determine if we need to stick after handling a request.
47 48 49 50 51 52 53 54 55 |
# File 'lib/gitlab/database/load_balancing/rack_middleware.rb', line 47 def stick_if_necessary(env) return unless ::Gitlab::Database::LoadBalancing::Session.current.performed_write? namespaces_and_ids = sticking_namespaces(env) namespaces_and_ids.each do |sticking, namespace, id| sticking.stick(namespace, id) end end |
#sticking_namespaces(env) ⇒ Object
Determines the sticking namespace and identifier based on the Rack environment.
For Rails requests this uses warden, but Grape and others have to manually set the right environment variable.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/gitlab/database/load_balancing/rack_middleware.rb', line 67 def sticking_namespaces(env) warden = env['warden'] if warden && warden.user # When sticking per user, _only_ sticking the main connection could # result in the application trying to read data from a different # connection, while that data isn't available yet. # # To prevent this from happening, we scope sticking to all the # models that support load balancing. In the future (if we # determined this to be OK) we may be able to relax this. ::Gitlab::Database::LoadBalancing.base_models.map do |model| [model.sticking, :user, warden.user.id] end elsif env[STICK_OBJECT].present? env[STICK_OBJECT].to_a else [] end end |