Commit 35bf427e authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Expire job and pipeline cache synchronously

This avoids the delay we are currently experiencing with scheduled
Sidekiq jobs and saves us from Sidekiq overhead.
parent c777b012
...@@ -236,9 +236,14 @@ module Ci ...@@ -236,9 +236,14 @@ module Ci
pipeline.run_after_commit do pipeline.run_after_commit do
PipelineHooksWorker.perform_async(pipeline.id) PipelineHooksWorker.perform_async(pipeline.id)
if Feature.enabled?(:expire_job_and_pipeline_cache_synchronously, pipeline.project, default_enabled: :yaml)
Ci::ExpirePipelineCacheService.new.execute(pipeline) # rubocop: disable CodeReuse/ServiceClass
else
ExpirePipelineCacheWorker.perform_async(pipeline.id) ExpirePipelineCacheWorker.perform_async(pipeline.id)
end end
end end
end
after_transition any => ::Ci::Pipeline.completed_statuses do |pipeline| after_transition any => ::Ci::Pipeline.completed_statuses do |pipeline|
pipeline.run_after_commit do pipeline.run_after_commit do
......
...@@ -188,9 +188,14 @@ class CommitStatus < Ci::ApplicationRecord ...@@ -188,9 +188,14 @@ class CommitStatus < Ci::ApplicationRecord
commit_status.run_after_commit do commit_status.run_after_commit do
PipelineProcessWorker.perform_async(pipeline_id) unless transition_options[:skip_pipeline_processing] PipelineProcessWorker.perform_async(pipeline_id) unless transition_options[:skip_pipeline_processing]
if Feature.enabled?(:expire_job_and_pipeline_cache_synchronously, project, default_enabled: :yaml)
expire_etag_cache!
else
ExpireJobCacheWorker.perform_async(id) ExpireJobCacheWorker.perform_async(id)
end end
end end
end
after_transition any => :failed do |commit_status| after_transition any => :failed do |commit_status|
commit_status.run_after_commit do commit_status.run_after_commit do
...@@ -301,6 +306,12 @@ class CommitStatus < Ci::ApplicationRecord ...@@ -301,6 +306,12 @@ class CommitStatus < Ci::ApplicationRecord
.update_all(retried: true, processed: true) .update_all(retried: true, processed: true)
end end
def expire_etag_cache!
job_path = Gitlab::Routing.url_helpers.project_build_path(project, id, format: :json)
Gitlab::EtagCaching::Store.new.touch(job_path)
end
private private
def unrecoverable_failure? def unrecoverable_failure?
......
...@@ -36,6 +36,10 @@ module Ci ...@@ -36,6 +36,10 @@ module Ci
update_pipeline! update_pipeline!
update_statuses_processed! update_statuses_processed!
if Feature.enabled?(:expire_job_and_pipeline_cache_synchronously, pipeline.project, default_enabled: :yaml)
Ci::ExpirePipelineCacheService.new.execute(pipeline)
end
true true
end end
......
...@@ -15,19 +15,10 @@ class ExpireJobCacheWorker # rubocop:disable Scalability/IdempotentWorker ...@@ -15,19 +15,10 @@ class ExpireJobCacheWorker # rubocop:disable Scalability/IdempotentWorker
idempotent! idempotent!
def perform(job_id) def perform(job_id)
job = CommitStatus.preload(:pipeline, :project).find_by_id(job_id) # rubocop: disable CodeReuse/ActiveRecord job = CommitStatus.find_by_id(job_id)
return unless job return unless job
pipeline = job.pipeline job.expire_etag_cache!
project = job.project ExpirePipelineCacheWorker.perform_async(job.pipeline_id)
Gitlab::EtagCaching::Store.new.touch(project_job_path(project, job))
ExpirePipelineCacheWorker.perform_async(pipeline.id)
end
private
def project_job_path(project, job)
Gitlab::Routing.url_helpers.project_build_path(project, job.id, format: :json)
end end
end end
---
name: expire_job_and_pipeline_cache_synchronously
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75611
rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1380
milestone: '14.6'
type: development
group: group::project management
default_enabled: false
...@@ -1503,12 +1503,32 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do ...@@ -1503,12 +1503,32 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end end
describe 'pipeline caching' do describe 'pipeline caching' do
context 'when expire_job_and_pipeline_cache_synchronously is enabled' do
before do
stub_feature_flags(expire_job_and_pipeline_cache_synchronously: true)
end
it 'executes Ci::ExpirePipelineCacheService' do
expect_next_instance_of(Ci::ExpirePipelineCacheService) do |service|
expect(service).to receive(:execute).with(pipeline)
end
pipeline.cancel
end
end
context 'when expire_job_and_pipeline_cache_synchronously is disabled' do
before do
stub_feature_flags(expire_job_and_pipeline_cache_synchronously: false)
end
it 'performs ExpirePipelinesCacheWorker' do it 'performs ExpirePipelinesCacheWorker' do
expect(ExpirePipelineCacheWorker).to receive(:perform_async).with(pipeline.id) expect(ExpirePipelineCacheWorker).to receive(:perform_async).with(pipeline.id)
pipeline.cancel pipeline.cancel
end end
end end
end
describe '#dangling?' do describe '#dangling?' do
it 'returns true if pipeline comes from any dangling sources' do it 'returns true if pipeline comes from any dangling sources' do
......
...@@ -46,11 +46,29 @@ RSpec.describe CommitStatus do ...@@ -46,11 +46,29 @@ RSpec.describe CommitStatus do
describe 'status state machine' do describe 'status state machine' do
let!(:commit_status) { create(:commit_status, :running, project: project) } let!(:commit_status) { create(:commit_status, :running, project: project) }
context 'when expire_job_and_pipeline_cache_synchronously is enabled' do
before do
stub_feature_flags(expire_job_and_pipeline_cache_synchronously: true)
end
it 'invalidates the cache after a transition' do
expect(commit_status).to receive(:expire_etag_cache!)
commit_status.success!
end
end
context 'when expire_job_and_pipeline_cache_synchronously is disabled' do
before do
stub_feature_flags(expire_job_and_pipeline_cache_synchronously: false)
end
it 'invalidates the cache after a transition' do it 'invalidates the cache after a transition' do
expect(ExpireJobCacheWorker).to receive(:perform_async).with(commit_status.id) expect(ExpireJobCacheWorker).to receive(:perform_async).with(commit_status.id)
commit_status.success! commit_status.success!
end end
end
describe 'transitioning to running' do describe 'transitioning to running' do
let(:commit_status) { create(:commit_status, :pending, started_at: nil) } let(:commit_status) { create(:commit_status, :pending, started_at: nil) }
...@@ -949,4 +967,15 @@ RSpec.describe CommitStatus do ...@@ -949,4 +967,15 @@ RSpec.describe CommitStatus do
described_class.bulk_insert_tags!(statuses, tag_list_by_build) described_class.bulk_insert_tags!(statuses, tag_list_by_build)
end end
end end
describe '#expire_etag_cache!' do
it 'expires the etag cache' do
expect_next_instance_of(Gitlab::EtagCaching::Store) do |etag_store|
job_path = Gitlab::Routing.url_helpers.project_build_path(project, commit_status.id, format: :json)
expect(etag_store).to receive(:touch).with(job_path)
end
commit_status.expire_etag_cache!
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