Class: Gitlab::Cache::Ci::ProjectPipelineStatus

Inherits:
Object
  • Object
show all
Includes:
Utils::StrongMemoize
Defined in:
lib/gitlab/cache/ci/project_pipeline_status.rb

Constant Summary collapse

STATUS_KEY_TTL =
8.hours

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project, pipeline_info: {}, loaded_from_cache: nil) ⇒ ProjectPipelineStatus

Returns a new instance of ProjectPipelineStatus.



40
41
42
43
44
45
46
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 40

def initialize(project, pipeline_info: {}, loaded_from_cache: nil)
  @project = project
  @sha = pipeline_info[:sha]
  @ref = pipeline_info[:ref]
  @status = pipeline_info[:status]
  @loaded = loaded_from_cache
end

Instance Attribute Details

#loadedObject

Returns the value of attribute loaded.



14
15
16
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 14

def loaded
  @loaded
end

#projectObject

Returns the value of attribute project.



14
15
16
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 14

def project
  @project
end

#refObject

Returns the value of attribute ref.



14
15
16
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 14

def ref
  @ref
end

#shaObject

Returns the value of attribute sha.



14
15
16
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 14

def sha
  @sha
end

#statusObject

Returns the value of attribute status.



14
15
16
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 14

def status
  @status
end

Class Method Details

.load_for_project(project) ⇒ Object



16
17
18
19
20
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 16

def self.load_for_project(project)
  new(project).tap do |status|
    status.load_status
  end
end

.load_in_batch_for_projects(projects) ⇒ Object



22
23
24
25
26
27
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 22

def self.load_in_batch_for_projects(projects)
  projects.each do |project|
    project.pipeline_status = new(project)
    project.pipeline_status.load_status
  end
end

.update_for_pipeline(pipeline) ⇒ Object



29
30
31
32
33
34
35
36
37
38
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 29

def self.update_for_pipeline(pipeline)
  pipeline_info = {
    sha: pipeline.sha,
    status: pipeline.status,
    ref: pipeline.ref
  }

  new(pipeline.project, pipeline_info: pipeline_info)
    .store_in_cache_if_needed
end

Instance Method Details

#cache_keyObject



126
127
128
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 126

def cache_key
  "#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:project:#{project.id}:pipeline_status"
end

#commitObject



130
131
132
133
134
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 130

def commit
  strong_memoize(:commit) do
    project.commit
  end
end

#delete_from_cacheObject



108
109
110
111
112
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 108

def delete_from_cache
  with_redis do |redis|
    redis.del(cache_key)
  end
end

#has_cache?Boolean

Returns:

  • (Boolean)


114
115
116
117
118
119
120
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 114

def has_cache?
  return self.loaded unless self.loaded.nil?

  with_redis do |redis|
    redis.exists?(cache_key) # rubocop:disable CodeReuse/ActiveRecord
  end
end

#has_status?Boolean

Returns:

  • (Boolean)


48
49
50
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 48

def has_status?
  loaded? && sha.present? && status.present?
end

#load_from_cacheObject



89
90
91
92
93
94
95
96
97
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 89

def load_from_cache
  with_redis do |redis|
    self.sha, self.status, self.ref = redis.hmget(cache_key, :sha, :status, :ref)

    self.status = nil if self.status.empty?

    redis.expire(cache_key, STATUS_KEY_TTL)
  end
end

#load_from_projectObject



69
70
71
72
73
74
75
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 69

def load_from_project
  return unless commit

  self.sha = commit.sha
  self.status = commit.status
  self.ref = project.repository.root_ref
end

#load_statusObject



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 52

def load_status
  return if loaded?

  if has_cache?
    load_from_cache
  else
    load_from_project
    store_in_cache
  end

  self.loaded = true
rescue GRPC::Unavailable, GRPC::DeadlineExceeded => e
  # Handle Gitaly connection issues gracefully
  Gitlab::ErrorTracking
    .track_exception(e, project_id: project.id)
end

#loaded?Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 122

def loaded?
  self.loaded
end

#store_in_cacheObject



99
100
101
102
103
104
105
106
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 99

def store_in_cache
  with_redis do |redis|
    redis.pipelined do |p|
      p.mapped_hmset(cache_key, { sha: sha, status: status, ref: ref })
      p.expire(cache_key, STATUS_KEY_TTL)
    end
  end
end

#store_in_cache_if_neededObject

We only cache the status for the HEAD commit of a project This status is rendered in project lists



79
80
81
82
83
84
85
86
87
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 79

def store_in_cache_if_needed
  return delete_from_cache unless commit
  return unless sha
  return unless ref

  if commit.sha == sha && project.repository.root_ref == ref
    store_in_cache
  end
end

#with_redis(&block) ⇒ Object



136
137
138
# File 'lib/gitlab/cache/ci/project_pipeline_status.rb', line 136

def with_redis(&block)
  Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
end