Commit 75317d7c authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch 'users_statistics_worker' into 'master'

Users statistics worker

See merge request gitlab-org/gitlab!27883
parents affc9e4e a9e9cc0f
...@@ -12,11 +12,25 @@ class UsersStatistics < ApplicationRecord ...@@ -12,11 +12,25 @@ class UsersStatistics < ApplicationRecord
:blocked :blocked
].freeze ].freeze
class << self
def create_current_stats!
stats_by_role = highest_role_stats
create!(
without_groups_and_projects: without_groups_and_projects_stats,
with_highest_role_guest: stats_by_role[:guest],
with_highest_role_reporter: stats_by_role[:reporter],
with_highest_role_developer: stats_by_role[:developer],
with_highest_role_maintainer: stats_by_role[:maintainer],
with_highest_role_owner: stats_by_role[:owner],
bots: bot_stats,
blocked: blocked_stats
)
end
private private
def highest_role_stats def highest_role_stats
return unless Feature.enabled?(:users_statistics)
{ {
owner: batch_count_for_access_level(Gitlab::Access::OWNER), owner: batch_count_for_access_level(Gitlab::Access::OWNER),
maintainer: batch_count_for_access_level(Gitlab::Access::MAINTAINER), maintainer: batch_count_for_access_level(Gitlab::Access::MAINTAINER),
...@@ -26,7 +40,20 @@ class UsersStatistics < ApplicationRecord ...@@ -26,7 +40,20 @@ class UsersStatistics < ApplicationRecord
} }
end end
def without_groups_and_projects_stats
batch_count_for_access_level(nil)
end
def bot_stats
Gitlab::Database::BatchCount.batch_count(User.bots)
end
def blocked_stats
Gitlab::Database::BatchCount.batch_count(User.blocked)
end
def batch_count_for_access_level(access_level) def batch_count_for_access_level(access_level)
Gitlab::Database::BatchCount.batch_count(UserHighestRole.with_highest_access_level(access_level)) Gitlab::Database::BatchCount.batch_count(UserHighestRole.with_highest_access_level(access_level))
end end
end
end end
...@@ -262,6 +262,13 @@ ...@@ -262,6 +262,13 @@
:resource_boundary: :unknown :resource_boundary: :unknown
:weight: 1 :weight: 1
:idempotent: :idempotent:
- :name: cronjob:users_create_statistics
:feature_category: :users
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent:
- :name: deployment:deployments_finished - :name: deployment:deployments_finished
:feature_category: :continuous_delivery :feature_category: :continuous_delivery
:has_external_dependencies: :has_external_dependencies:
......
# frozen_string_literal: true
module Users
class CreateStatisticsWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
# rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category :users
def perform
UsersStatistics.create_current_stats!
rescue ActiveRecord::RecordInvalid => exception
Gitlab::ErrorTracking.track_exception(exception)
end
end
end
---
title: Add daily job to create users statistics
merge_request: 27883
author:
type: added
...@@ -552,6 +552,9 @@ Gitlab.ee do ...@@ -552,6 +552,9 @@ Gitlab.ee do
Settings.cron_jobs['sync_seat_link_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['sync_seat_link_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['sync_seat_link_worker']['cron'] ||= "#{rand(60)} 0 * * *" Settings.cron_jobs['sync_seat_link_worker']['cron'] ||= "#{rand(60)} 0 * * *"
Settings.cron_jobs['sync_seat_link_worker']['job_class'] = 'SyncSeatLinkWorker' Settings.cron_jobs['sync_seat_link_worker']['job_class'] = 'SyncSeatLinkWorker'
Settings.cron_jobs['users_create_statistics_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['users_create_statistics_worker']['cron'] ||= '2 15 * * *'
Settings.cron_jobs['users_create_statistics_worker']['job_class'] = 'Users::CreateStatisticsWorker'
end end
# #
......
# frozen_string_literal: true
FactoryBot.define do
factory :users_statistics do
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe UsersStatistics do
describe '.create_current_stats!' do
before do
create_list(:user_highest_role, 4)
create_list(:user_highest_role, 2, :guest)
create_list(:user_highest_role, 3, :reporter)
create_list(:user_highest_role, 4, :developer)
create_list(:user_highest_role, 3, :maintainer)
create_list(:user_highest_role, 2, :owner)
create_list(:user, 2, :bot)
create_list(:user, 1, :blocked)
allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
end
context 'when successful' do
it 'creates an entry with the current statistics values' do
expect(described_class.create_current_stats!).to have_attributes(
without_groups_and_projects: 4,
with_highest_role_guest: 2,
with_highest_role_reporter: 3,
with_highest_role_developer: 4,
with_highest_role_maintainer: 3,
with_highest_role_owner: 2,
bots: 2,
blocked: 1
)
end
end
context 'when unsuccessful' do
it 'raises an ActiveRecord::RecordInvalid exception' do
allow(UsersStatistics).to receive(:create!).and_raise(ActiveRecord::RecordInvalid)
expect { described_class.create_current_stats! }.to raise_error(ActiveRecord::RecordInvalid)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Users::CreateStatisticsWorker do
describe '#perform' do
subject { described_class.new.perform }
before do
allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
end
context 'when successful' do
it 'create an users statistics entry' do
expect { subject }.to change { UsersStatistics.count }.from(0).to(1)
end
end
context 'when unsuccessful' do
it 'logs an error' do
users_statistics = build(:users_statistics)
users_statistics.errors.add(:base, 'This is an error')
exception = ActiveRecord::RecordInvalid.new(users_statistics)
allow(UsersStatistics).to receive(:create_current_stats!).and_raise(exception)
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(exception).and_call_original
subject
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment