Skip to content
Snippets Groups Projects
Commit 6a915d6f authored by Toon Claes's avatar Toon Claes
Browse files

Limit `update_tracked_fields` to write to database once/hour

Every time a user logs in or out, the Trackable attributes are written to the
database. This is causing a lot of load on the database, for data that isn't
really critical.

So to avoid the database being hammered, add a Gitlab::ExclusiveLease before
writing trackable attributes to the database. This lease expires after an hour,
so only when the attributes were written more than an hour ago, they can be
written again. Otherwise they are ignored.
parent 8b9cd3c0
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -40,6 +40,16 @@ class User < ActiveRecord::Base
devise :lockable, :recoverable, :rememberable, :trackable,
:validatable, :omniauthable, :confirmable, :registerable
 
# Limit trackable fields to update at most once every hour
alias_method :devise_update_tracked_fields!, :update_tracked_fields!
def update_tracked_fields!(request)
lease = Gitlab::ExclusiveLease.new("user_update_tracked_fields:#{id}", timeout: 1.hour.to_i)
return unless lease.try_obtain
devise_update_tracked_fields!(request)
end
attr_accessor :force_random_password
 
# Virtual attribute for authenticating by either username or email
Loading
Loading
---
title: "Limit User's trackable attributes, like `current_sign_in_at`, to update at most once/hour"
merge_request: 11053
author:
Loading
Loading
@@ -344,6 +344,25 @@ describe User, models: true do
end
end
 
describe '#update_tracked_fields!', :redis do
let(:request) { OpenStruct.new(remote_ip: "127.0.0.1") }
let(:user) { create(:user) }
it 'writes trackable attributes' do
expect do
user.update_tracked_fields!(request)
end.to change { user.reload.current_sign_in_at }
end
it 'does not write trackable attributes when called a second time within the hour' do
user.update_tracked_fields!(request)
expect do
user.update_tracked_fields!(request)
end.not_to change { user.current_sign_in_at }
end
end
shared_context 'user keys' do
let(:user) { create(:user) }
let!(:key) { create(:key, user: user) }
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment