Commit 3b4af59a authored by Yorick Peterse's avatar Yorick Peterse

Don't schedule ProjectCacheWorker unless needed

This changes ProjectCacheWorker.perform_async so it only schedules a job
when no lease for the given project is present. This ensures we don't
end up scheduling hundreds of jobs when they won't be executed anyway.
parent 9a677038
No related merge requests found
......@@ -27,6 +27,7 @@ Please view this file on the master branch, on stable branches it's out of date.
- Fix unauthorized users dragging on issue boards
- Better handle when no users were selected for adding to group or project. (Linus Thiel)
- Only show register tab if signup enabled.
- Only schedule ProjectCacheWorker jobs when needed
## 8.13.0 (2016-10-22)
- Removes extra line for empty issue description. (!7045)
......
......@@ -9,6 +9,18 @@ class ProjectCacheWorker
LEASE_TIMEOUT = 15.minutes.to_i
def self.lease_for(project_id)
Gitlab::ExclusiveLease.
new("project_cache_worker:#{project_id}", timeout: LEASE_TIMEOUT)
end
# Overwrite Sidekiq's implementation so we only schedule when actually needed.
def self.perform_async(project_id)
# If a lease for this project is still being held there's no point in
# scheduling a new job.
super unless lease_for(project_id).exists?
end
def perform(project_id)
if try_obtain_lease_for(project_id)
Rails.logger.
......@@ -37,8 +49,6 @@ class ProjectCacheWorker
end
def try_obtain_lease_for(project_id)
Gitlab::ExclusiveLease.
new("project_cache_worker:#{project_id}", timeout: LEASE_TIMEOUT).
try_obtain
self.class.lease_for(project_id).try_obtain
end
end
......@@ -48,6 +48,13 @@ module Gitlab
end
end
# Returns true if the key for this lease is set.
def exists?
Gitlab::Redis.with do |redis|
redis.exists(redis_key)
end
end
# No #cancel method. See comments above!
private
......
require 'spec_helper'
describe Gitlab::ExclusiveLease do
describe Gitlab::ExclusiveLease, type: :redis do
let(:unique_key) { SecureRandom.hex(10) }
describe '#try_obtain' do
it 'cannot obtain twice before the lease has expired' do
lease = Gitlab::ExclusiveLease.new(unique_key, timeout: 3600)
expect(lease.try_obtain).to eq(true)
......@@ -14,8 +17,20 @@ describe Gitlab::ExclusiveLease do
sleep(2 * timeout) # lease should have expired now
expect(lease.try_obtain).to eq(true)
end
end
def unique_key
SecureRandom.hex(10)
describe '#exists?' do
it 'returns true for an existing lease' do
lease = Gitlab::ExclusiveLease.new(unique_key, timeout: 3600)
lease.try_obtain
expect(lease.exists?).to eq(true)
end
it 'returns false for a lease that does not exist' do
lease = Gitlab::ExclusiveLease.new(unique_key, timeout: 3600)
expect(lease.exists?).to eq(false)
end
end
end
......@@ -50,6 +50,12 @@ RSpec.configure do |config|
example.run
Rails.cache = caching_store
end
config.around(:each, :redis) do |example|
Gitlab::Redis.with(&:flushall)
example.run
Gitlab::Redis.with(&:flushall)
end
end
FactoryGirl::SyntaxRunner.class_eval do
......
......@@ -5,6 +5,26 @@ describe ProjectCacheWorker do
subject { described_class.new }
describe '.perform_async' do
it 'schedules the job when no lease exists' do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:exists?).
and_return(false)
expect_any_instance_of(described_class).to receive(:perform)
described_class.perform_async(project.id)
end
it 'does not schedule the job when a lease exists' do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:exists?).
and_return(true)
expect_any_instance_of(described_class).not_to receive(:perform)
described_class.perform_async(project.id)
end
end
describe '#perform' do
context 'when an exclusive lease can be obtained' do
before do
......
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