gitlab-exporter 16.0.0 → 16.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +12 -2
- data/.rubocop_todo.yml +17 -28
- data/Gemfile +1 -2
- data/Gemfile.lock +41 -32
- data/gitlab-exporter.gemspec +6 -6
- data/lib/gitlab_exporter/cli.rb +10 -10
- data/lib/gitlab_exporter/database/ci_builds.rb +1 -1
- data/lib/gitlab_exporter/database/row_count.rb +2 -2
- data/lib/gitlab_exporter/database/zoekt.rb +94 -19
- data/lib/gitlab_exporter/git.rb +5 -5
- data/lib/gitlab_exporter/memstats/mapping.rb +2 -16
- data/lib/gitlab_exporter/prober.rb +1 -1
- data/lib/gitlab_exporter/tls_helper.rb +1 -1
- data/lib/gitlab_exporter/version.rb +1 -1
- data/spec/database/bloat_spec.rb +2 -2
- data/spec/database/row_count_spec.rb +11 -11
- data/spec/database/zoekt_spec.rb +63 -21
- metadata +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60e275e1cea2b8841c1c8471f44d851a49b552ede909c91aca462ad60efcd3ab
|
4
|
+
data.tar.gz: 59c1f60fc4caed54da0048db13c3dd1566fd70bbb744f3260c16cca78012c018
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e790d3ec4ebb7e07546d5565dc14fdc62f1131b3b23cf367c502eb12e7d7ed55051dd79fed6e8c865af464d1b120eaf2fe6f4f72f3a6a581915adc342b446ad2
|
7
|
+
data.tar.gz: 829b42af76274c5ff4b25c9094545ea42491fc41f16bae2dec96cd3a76450beb7cca40496bbc10f926f75b0bcaa509fb9a4001a3f83b2e7dc3f1031b7554d0d3
|
data/.gitlab-ci.yml
CHANGED
@@ -7,7 +7,7 @@ include:
|
|
7
7
|
- template: Security/Dependency-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
|
8
8
|
|
9
9
|
variables:
|
10
|
-
RUBY_VERSION: "3.
|
10
|
+
RUBY_VERSION: "3.3"
|
11
11
|
|
12
12
|
stages:
|
13
13
|
- test
|
@@ -17,6 +17,7 @@ stages:
|
|
17
17
|
default:
|
18
18
|
image: ruby:${RUBY_VERSION}
|
19
19
|
cache:
|
20
|
+
key: ruby-${RUBY_VERSION}
|
20
21
|
paths:
|
21
22
|
- vendor
|
22
23
|
tags:
|
@@ -26,6 +27,15 @@ default:
|
|
26
27
|
- git config --global user.email "bot@gitlab.com"
|
27
28
|
- git config --global user.name "Bot User"
|
28
29
|
- bundle config set --local deployment true
|
30
|
+
- |
|
31
|
+
# Bundler 2.7.1 and up require Ruby 3.2 and up, so
|
32
|
+
# to avoid https://github.com/rubygems/rubygems/issues/5380 use an
|
33
|
+
# older Bundler version.
|
34
|
+
case ${RUBY_VERSION} in
|
35
|
+
"3.0"|"3.1")
|
36
|
+
export BUNDLER_VERSION="2.4.20"
|
37
|
+
;;
|
38
|
+
esac
|
29
39
|
- bundle install -j $(nproc)
|
30
40
|
|
31
41
|
workflow:
|
@@ -52,7 +62,7 @@ rspec_integration:
|
|
52
62
|
services:
|
53
63
|
- name: redis:${REDIS_VERSION}
|
54
64
|
alias: redis-master
|
55
|
-
- name:
|
65
|
+
- name: bitnamilegacy/redis-sentinel:${REDIS_SENTINEL_VERSION}
|
56
66
|
alias: redis-sentinel
|
57
67
|
command:
|
58
68
|
- /bin/sh
|
data/.rubocop_todo.yml
CHANGED
@@ -1,19 +1,14 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on
|
3
|
+
# on 2025-08-06 20:59:18 UTC using RuboCop version 1.79.1.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
|
-
# Offense count: 1
|
10
|
-
# Configuration parameters: Include.
|
11
|
-
# Include: **/*.gemspec
|
12
|
-
Gemspec/RequiredRubyVersion:
|
13
|
-
Exclude:
|
14
|
-
- 'gitlab-exporter.gemspec'
|
15
|
-
|
16
9
|
# Offense count: 3
|
10
|
+
# This cop supports safe autocorrection (--autocorrect).
|
11
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
17
12
|
Lint/AmbiguousBlockAssociation:
|
18
13
|
Exclude:
|
19
14
|
- 'spec/git_spec.rb'
|
@@ -26,38 +21,32 @@ Lint/MissingCopEnableDirective:
|
|
26
21
|
- 'spec/database/ci_builds_spec.rb'
|
27
22
|
- 'spec/git_process_proper_spec.rb'
|
28
23
|
|
29
|
-
# Offense count:
|
30
|
-
#
|
31
|
-
|
32
|
-
Exclude:
|
33
|
-
- 'spec/spec_helper.rb'
|
34
|
-
|
35
|
-
# Offense count: 16
|
36
|
-
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods.
|
37
|
-
# ExcludedMethods: refine
|
24
|
+
# Offense count: 24
|
25
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
26
|
+
# AllowedMethods: refine
|
38
27
|
Metrics/BlockLength:
|
39
|
-
Max:
|
28
|
+
Max: 297
|
40
29
|
|
41
|
-
# Offense count:
|
42
|
-
# Configuration parameters:
|
30
|
+
# Offense count: 2
|
31
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
43
32
|
Metrics/CyclomaticComplexity:
|
44
33
|
Max: 8
|
45
34
|
|
46
35
|
# Offense count: 1
|
47
|
-
# Configuration parameters:
|
36
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
48
37
|
Metrics/PerceivedComplexity:
|
49
38
|
Max: 9
|
50
39
|
|
51
40
|
# Offense count: 1
|
52
|
-
# Configuration parameters:
|
53
|
-
#
|
54
|
-
Style/
|
41
|
+
# Configuration parameters: AllowedMethods.
|
42
|
+
# AllowedMethods: respond_to_missing?
|
43
|
+
Style/OptionalBooleanParameter:
|
55
44
|
Exclude:
|
56
|
-
- 'lib/gitlab_exporter/
|
45
|
+
- 'lib/gitlab_exporter/prometheus.rb'
|
57
46
|
|
58
|
-
# Offense count:
|
59
|
-
#
|
60
|
-
# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods.
|
47
|
+
# Offense count: 3
|
48
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
49
|
+
# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength.
|
61
50
|
# AllowedMethods: present?, blank?, presence, try, try!
|
62
51
|
Style/SafeNavigation:
|
63
52
|
Exclude:
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
gitlab-exporter (16.
|
5
|
-
connection_pool (= 2.5.
|
4
|
+
gitlab-exporter (16.2.0)
|
5
|
+
connection_pool (= 2.5.4)
|
6
6
|
deep_merge (~> 1.2.2)
|
7
|
-
faraday (= 2.
|
8
|
-
pg (= 1.
|
9
|
-
puma (= 6.6.
|
7
|
+
faraday (= 2.14.0)
|
8
|
+
pg (= 1.6.2)
|
9
|
+
puma (= 6.6.1)
|
10
10
|
quantile (= 0.2.1)
|
11
|
-
redis (= 4.
|
12
|
-
redis-namespace (= 1.
|
11
|
+
redis (= 4.8.1)
|
12
|
+
redis-namespace (= 1.11.0)
|
13
13
|
sidekiq (= 6.5.12)
|
14
14
|
sinatra (~> 3.2.0)
|
15
15
|
webrick (~> 1.9)
|
@@ -17,38 +17,42 @@ PATH
|
|
17
17
|
GEM
|
18
18
|
remote: https://rubygems.org/
|
19
19
|
specs:
|
20
|
-
ast (2.4.
|
20
|
+
ast (2.4.3)
|
21
21
|
base64 (0.2.0)
|
22
|
-
connection_pool (2.5.
|
22
|
+
connection_pool (2.5.4)
|
23
23
|
deep_merge (1.2.2)
|
24
24
|
diff-lcs (1.5.0)
|
25
|
-
faraday (2.
|
25
|
+
faraday (2.14.0)
|
26
26
|
faraday-net_http (>= 2.0, < 3.5)
|
27
27
|
json
|
28
28
|
logger
|
29
29
|
faraday-net_http (3.0.2)
|
30
30
|
json (2.13.2)
|
31
|
+
language_server-protocol (3.17.0.5)
|
32
|
+
lint_roller (1.1.0)
|
31
33
|
logger (1.7.0)
|
32
34
|
mustermann (3.0.3)
|
33
35
|
ruby2_keywords (~> 0.0.1)
|
34
36
|
nio4r (2.7.4)
|
35
|
-
parallel (1.
|
36
|
-
parser (3.
|
37
|
+
parallel (1.27.0)
|
38
|
+
parser (3.3.9.0)
|
37
39
|
ast (~> 2.4.1)
|
38
|
-
|
39
|
-
|
40
|
+
racc
|
41
|
+
pg (1.6.2)
|
42
|
+
prism (1.4.0)
|
43
|
+
puma (6.6.1)
|
40
44
|
nio4r (~> 2.0)
|
41
45
|
quantile (0.2.1)
|
46
|
+
racc (1.8.1)
|
42
47
|
rack (2.2.15)
|
43
48
|
rack-protection (3.2.0)
|
44
49
|
base64 (>= 0.1.0)
|
45
50
|
rack (~> 2.2, >= 2.2.4)
|
46
|
-
rainbow (3.
|
47
|
-
redis (4.
|
48
|
-
redis-namespace (1.
|
51
|
+
rainbow (3.1.1)
|
52
|
+
redis (4.8.1)
|
53
|
+
redis-namespace (1.11.0)
|
49
54
|
redis (>= 4)
|
50
|
-
regexp_parser (2.0
|
51
|
-
rexml (3.2.4)
|
55
|
+
regexp_parser (2.11.0)
|
52
56
|
rspec (3.12.0)
|
53
57
|
rspec-core (~> 3.12.0)
|
54
58
|
rspec-expectations (~> 3.12.0)
|
@@ -62,18 +66,21 @@ GEM
|
|
62
66
|
diff-lcs (>= 1.2.0, < 2.0)
|
63
67
|
rspec-support (~> 3.12.0)
|
64
68
|
rspec-support (3.12.0)
|
65
|
-
rubocop (
|
69
|
+
rubocop (1.81.1)
|
70
|
+
json (~> 2.3)
|
71
|
+
language_server-protocol (~> 3.17.0.2)
|
72
|
+
lint_roller (~> 1.1.0)
|
66
73
|
parallel (~> 1.10)
|
67
|
-
parser (>=
|
74
|
+
parser (>= 3.3.0.2)
|
68
75
|
rainbow (>= 2.2.2, < 4.0)
|
69
|
-
regexp_parser (>=
|
70
|
-
|
71
|
-
rubocop-ast (>= 0.6.0)
|
76
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
77
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
72
78
|
ruby-progressbar (~> 1.7)
|
73
|
-
unicode-display_width (>=
|
74
|
-
rubocop-ast (1.
|
75
|
-
parser (>=
|
76
|
-
|
79
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
80
|
+
rubocop-ast (1.47.1)
|
81
|
+
parser (>= 3.3.7.2)
|
82
|
+
prism (~> 1.4)
|
83
|
+
ruby-progressbar (1.13.0)
|
77
84
|
ruby2_keywords (0.0.5)
|
78
85
|
sidekiq (6.5.12)
|
79
86
|
connection_pool (>= 2.2.5, < 3)
|
@@ -85,7 +92,9 @@ GEM
|
|
85
92
|
rack-protection (= 3.2.0)
|
86
93
|
tilt (~> 2.0)
|
87
94
|
tilt (2.6.0)
|
88
|
-
unicode-display_width (1.
|
95
|
+
unicode-display_width (3.1.4)
|
96
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
97
|
+
unicode-emoji (4.0.4)
|
89
98
|
webrick (1.9.1)
|
90
99
|
|
91
100
|
PLATFORMS
|
@@ -93,9 +102,9 @@ PLATFORMS
|
|
93
102
|
|
94
103
|
DEPENDENCIES
|
95
104
|
gitlab-exporter!
|
96
|
-
rspec (~> 3.12)
|
105
|
+
rspec (~> 3.12.0)
|
97
106
|
rspec-expectations (~> 3.12.0)
|
98
|
-
rubocop (~> 0
|
107
|
+
rubocop (~> 1.0)
|
99
108
|
|
100
109
|
BUNDLED WITH
|
101
|
-
2.
|
110
|
+
2.7.1
|
data/gitlab-exporter.gemspec
CHANGED
@@ -22,14 +22,14 @@ Gem::Specification.new do |s|
|
|
22
22
|
|
23
23
|
s.required_ruby_version = Gem::Requirement.new(">= 3.0")
|
24
24
|
|
25
|
-
s.add_runtime_dependency "connection_pool", "2.5.
|
25
|
+
s.add_runtime_dependency "connection_pool", "2.5.4"
|
26
26
|
s.add_runtime_dependency "deep_merge", "~> 1.2.2"
|
27
|
-
s.add_runtime_dependency "faraday", "2.
|
28
|
-
s.add_runtime_dependency "pg", "1.
|
29
|
-
s.add_runtime_dependency "puma", "6.6.
|
27
|
+
s.add_runtime_dependency "faraday", "2.14.0"
|
28
|
+
s.add_runtime_dependency "pg", "1.6.2"
|
29
|
+
s.add_runtime_dependency "puma", "6.6.1"
|
30
30
|
s.add_runtime_dependency "quantile", "0.2.1"
|
31
|
-
s.add_runtime_dependency "redis", "4.
|
32
|
-
s.add_runtime_dependency "redis-namespace", "1.
|
31
|
+
s.add_runtime_dependency "redis", "4.8.1"
|
32
|
+
s.add_runtime_dependency "redis-namespace", "1.11.0"
|
33
33
|
s.add_runtime_dependency "sidekiq", "6.5.12"
|
34
34
|
s.add_runtime_dependency "sinatra", "~> 3.2.0"
|
35
35
|
s.add_runtime_dependency "webrick", "~> 1.9"
|
data/lib/gitlab_exporter/cli.rb
CHANGED
@@ -44,7 +44,7 @@ module GitLab
|
|
44
44
|
@options = options(args)
|
45
45
|
args = @options.parse!
|
46
46
|
@source = args.shift
|
47
|
-
@target = args.shift ||
|
47
|
+
@target = args.shift || $stdout
|
48
48
|
@labels ||= {}
|
49
49
|
end
|
50
50
|
|
@@ -79,7 +79,7 @@ module GitLab
|
|
79
79
|
|
80
80
|
# Database tuple stats runner.
|
81
81
|
#
|
82
|
-
# It will take a database connection string and print results to
|
82
|
+
# It will take a database connection string and print results to $stdout
|
83
83
|
class DatabaseTupleStats
|
84
84
|
COMMAND_NAME = "db-tuple-stats".freeze
|
85
85
|
|
@@ -87,7 +87,7 @@ module GitLab
|
|
87
87
|
@options = options(args)
|
88
88
|
@options.parse!
|
89
89
|
|
90
|
-
@target = args.shift ||
|
90
|
+
@target = args.shift || $stdout
|
91
91
|
@target = File.open(@target, "a") if @target.is_a?(String)
|
92
92
|
end
|
93
93
|
|
@@ -121,7 +121,7 @@ module GitLab
|
|
121
121
|
|
122
122
|
# Database row counts query runner.
|
123
123
|
#
|
124
|
-
# This will take the database connection and print the result to
|
124
|
+
# This will take the database connection and print the result to $stdout
|
125
125
|
class DatabaseRowCounts
|
126
126
|
COMMAND_NAME = "row-counts".freeze
|
127
127
|
|
@@ -129,7 +129,7 @@ module GitLab
|
|
129
129
|
@options = options(args)
|
130
130
|
@options.parse!
|
131
131
|
|
132
|
-
@target = args.shift ||
|
132
|
+
@target = args.shift || $stdout
|
133
133
|
@target = File.open(@target, "a") if @target.is_a?(String)
|
134
134
|
end
|
135
135
|
|
@@ -234,7 +234,7 @@ module GitLab
|
|
234
234
|
@options = options(args)
|
235
235
|
@options.parse!
|
236
236
|
|
237
|
-
@target = args.shift ||
|
237
|
+
@target = args.shift || $stdout
|
238
238
|
@target = File.open(@target, "a") if @target.is_a?(String)
|
239
239
|
end
|
240
240
|
|
@@ -271,7 +271,7 @@ module GitLab
|
|
271
271
|
|
272
272
|
# Sidekiq runner.
|
273
273
|
#
|
274
|
-
# It will take a Redis connection URL and print results to
|
274
|
+
# It will take a Redis connection URL and print results to $stdout
|
275
275
|
class SidekiqRunner
|
276
276
|
COMMAND_NAME = "sidekiq".freeze
|
277
277
|
|
@@ -279,7 +279,7 @@ module GitLab
|
|
279
279
|
@options = options(args)
|
280
280
|
@options.parse!
|
281
281
|
|
282
|
-
@target = args.shift ||
|
282
|
+
@target = args.shift || $stdout
|
283
283
|
@target = File.open(@target, "a") if @target.is_a?(String)
|
284
284
|
end
|
285
285
|
|
@@ -315,7 +315,7 @@ module GitLab
|
|
315
315
|
redis_sentinels: @redis_sentinels,
|
316
316
|
redis_sentinel_username: @redis_sentinel_username,
|
317
317
|
redis_sentinel_password: @redis_sentinel_password,
|
318
|
-
logger: Logger.new(
|
318
|
+
logger: Logger.new($stderr))
|
319
319
|
|
320
320
|
prober
|
321
321
|
.probe_stats
|
@@ -343,7 +343,7 @@ module GitLab
|
|
343
343
|
@options = options(args)
|
344
344
|
@options.parse!
|
345
345
|
|
346
|
-
@target = args.shift ||
|
346
|
+
@target = args.shift || $stdout
|
347
347
|
@target = File.open(@target, "a") if @target.is_a?(String)
|
348
348
|
end
|
349
349
|
|
@@ -191,7 +191,7 @@ module GitLab
|
|
191
191
|
results = []
|
192
192
|
|
193
193
|
query = ee? ? BUILDS_QUERY_EE : BUILDS_QUERY_CE
|
194
|
-
query
|
194
|
+
query %= [status]
|
195
195
|
exec_query_with_custom_random_page_cost(query).each do |row|
|
196
196
|
results << transform_builds_row_to_values(row)
|
197
197
|
end
|
@@ -202,7 +202,7 @@ module GitLab
|
|
202
202
|
|
203
203
|
result.map do |row|
|
204
204
|
labels = {}
|
205
|
-
(query_hash[:fields] ||
|
205
|
+
(query_hash[:fields] || {}).each_key do |key| labels[key] = row[key.to_s] end
|
206
206
|
{ "count": row["count"], "labels": labels }
|
207
207
|
end
|
208
208
|
end
|
@@ -233,7 +233,7 @@ module GitLab
|
|
233
233
|
query_string << " FROM #{query[:select]}"
|
234
234
|
query_string << " #{query[:joins]}" if query[:joins]
|
235
235
|
query_string << " WHERE #{query[:where]}" if query[:where]
|
236
|
-
query_string << " GROUP BY
|
236
|
+
query_string << " GROUP BY #{query[:fields].keys.join(', ')}" if query[:fields]
|
237
237
|
query_string << ";"
|
238
238
|
end
|
239
239
|
end
|
@@ -3,45 +3,100 @@ module GitLab
|
|
3
3
|
module Database
|
4
4
|
# A helper class to collect zoekt metrics.
|
5
5
|
class ZoektCollector < Base
|
6
|
-
|
6
|
+
# Query to get processing zoekt_tasks distribution by zoekt_node_id
|
7
|
+
ZOEKT_TASKS_PROCESSING_QUERY = <<~SQL.freeze
|
7
8
|
WITH task_counts AS (
|
8
|
-
SELECT
|
9
|
+
SELECT
|
9
10
|
zoekt_node_id,
|
10
11
|
COUNT(*) AS count
|
11
|
-
FROM
|
12
|
+
FROM
|
12
13
|
zoekt_tasks
|
13
|
-
WHERE
|
14
|
+
WHERE
|
14
15
|
perform_at <= $1
|
15
16
|
AND state IN (0, 1)
|
16
|
-
GROUP BY
|
17
|
+
GROUP BY
|
17
18
|
zoekt_node_id
|
18
19
|
)
|
19
|
-
SELECT
|
20
|
+
SELECT
|
20
21
|
n.id AS node_id,
|
21
22
|
n.metadata ->> 'name' AS node_name,
|
22
23
|
COALESCE(tc.count, 0) AS task_count
|
23
|
-
FROM
|
24
|
+
FROM
|
24
25
|
zoekt_nodes n
|
25
|
-
LEFT JOIN
|
26
|
+
LEFT JOIN
|
26
27
|
task_counts tc ON n.id = tc.zoekt_node_id
|
27
28
|
SQL
|
28
29
|
|
30
|
+
ZOEKT_NODES_QUERY = <<~SQL.freeze
|
31
|
+
SELECT schema_version, id FROM zoekt_nodes
|
32
|
+
SQL
|
33
|
+
|
34
|
+
ZOEKT_REPOSITORY_SCHEMA_VERSION_QUERY = <<~SQL.freeze
|
35
|
+
SELECT
|
36
|
+
COUNT(*)
|
37
|
+
FROM
|
38
|
+
zoekt_repositories
|
39
|
+
INNER JOIN
|
40
|
+
zoekt_indices
|
41
|
+
ON zoekt_repositories.zoekt_index_id = zoekt_indices.id
|
42
|
+
WHERE
|
43
|
+
zoekt_indices.zoekt_node_id = $1
|
44
|
+
AND zoekt_repositories.schema_version < $2
|
45
|
+
AND zoekt_repositories.state = 10;
|
46
|
+
SQL
|
47
|
+
|
29
48
|
ZOEKT_ENABLED_QUERY = <<~SQL.freeze
|
30
49
|
SELECT
|
31
|
-
zoekt_settings ->> 'zoekt_indexing_enabled' AS zoekt_indexing_enabled
|
50
|
+
zoekt_settings ->> 'zoekt_indexing_enabled' AS zoekt_indexing_enabled
|
32
51
|
FROM application_settings
|
33
52
|
ORDER BY ID DESC
|
34
53
|
LIMIT 1
|
35
54
|
SQL
|
36
55
|
|
37
56
|
def run
|
38
|
-
return unless zoekt_indexing_enabled?
|
57
|
+
return {} unless zoekt_indexing_enabled?
|
39
58
|
|
40
|
-
|
59
|
+
{
|
60
|
+
task_processing_query_result: execute(ZOEKT_TASKS_PROCESSING_QUERY, [Time.now.utc]),
|
61
|
+
repositories_schema_version_query_result: repositories_schema_version_query_result
|
62
|
+
}.compact
|
41
63
|
end
|
42
64
|
|
43
65
|
private
|
44
66
|
|
67
|
+
def repositories_schema_version_query_result
|
68
|
+
hash = zoekt_node_schema_version_hash
|
69
|
+
return if hash.nil?
|
70
|
+
|
71
|
+
zoekt_repository_schema_version_result(hash)
|
72
|
+
end
|
73
|
+
|
74
|
+
def zoekt_node_schema_version_hash
|
75
|
+
zoekt_nodes = execute(ZOEKT_NODES_QUERY)
|
76
|
+
return if zoekt_nodes.nil?
|
77
|
+
|
78
|
+
hash = {}
|
79
|
+
zoekt_nodes.each do |row|
|
80
|
+
hash[row["id"]] = row["schema_version"]
|
81
|
+
end
|
82
|
+
hash
|
83
|
+
end
|
84
|
+
|
85
|
+
def zoekt_repository_schema_version_result(hash)
|
86
|
+
result = Set.new
|
87
|
+
hash.each do |id, schema_version|
|
88
|
+
query_result = execute(ZOEKT_REPOSITORY_SCHEMA_VERSION_QUERY, [id, schema_version])
|
89
|
+
if query_result.nil?
|
90
|
+
result = nil
|
91
|
+
break
|
92
|
+
end
|
93
|
+
|
94
|
+
count = query_result[0]["count"].to_i
|
95
|
+
result.add({ target_schema_version: schema_version, zoekt_node_id: id, unfinished_repository_count: count })
|
96
|
+
end
|
97
|
+
result
|
98
|
+
end
|
99
|
+
|
45
100
|
def zoekt_indexing_enabled?
|
46
101
|
@zoekt_indexing_enabled ||=
|
47
102
|
begin
|
@@ -53,7 +108,7 @@ module GitLab
|
|
53
108
|
end
|
54
109
|
end
|
55
110
|
|
56
|
-
def execute(query, params)
|
111
|
+
def execute(query, params = [])
|
57
112
|
with_connection_pool do |conn|
|
58
113
|
conn.exec_params(query, params)
|
59
114
|
end
|
@@ -68,6 +123,10 @@ module GitLab
|
|
68
123
|
"Number of tasks waiting to be processed by Zoekt",
|
69
124
|
"gauge")
|
70
125
|
|
126
|
+
PrometheusMetrics.describe("search_zoekt_repositories_schema_version_count",
|
127
|
+
"Number of zoekt_repositories which do not have the latest schema version",
|
128
|
+
"gauge")
|
129
|
+
|
71
130
|
def initialize(metrics: PrometheusMetrics.new, **opts)
|
72
131
|
@metrics = metrics
|
73
132
|
@collector = opts[:collector] || ZoektCollector.new(**opts)
|
@@ -75,13 +134,11 @@ module GitLab
|
|
75
134
|
|
76
135
|
def probe_db
|
77
136
|
results = @collector.run
|
78
|
-
results.to_a.each do |row|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
node_id: row["node_id"]
|
84
|
-
)
|
137
|
+
results[:task_processing_query_result].to_a.each do |row|
|
138
|
+
add_processing_zoekt_tasks_to_metric(row)
|
139
|
+
end
|
140
|
+
results[:repositories_schema_version_query_result]&.each do |row|
|
141
|
+
add_zoekt_repositories_by_schema_version_to_metric(row)
|
85
142
|
end
|
86
143
|
|
87
144
|
self
|
@@ -89,6 +146,24 @@ module GitLab
|
|
89
146
|
self
|
90
147
|
end
|
91
148
|
|
149
|
+
def add_processing_zoekt_tasks_to_metric(row)
|
150
|
+
@metrics.add(
|
151
|
+
"search_zoekt_task_processing_queue_size",
|
152
|
+
row["task_count"].to_i,
|
153
|
+
node_name: row["node_name"],
|
154
|
+
node_id: row["node_id"]
|
155
|
+
)
|
156
|
+
end
|
157
|
+
|
158
|
+
def add_zoekt_repositories_by_schema_version_to_metric(row)
|
159
|
+
@metrics.add(
|
160
|
+
"search_zoekt_repositories_schema_version_count",
|
161
|
+
row[:unfinished_repository_count].to_i,
|
162
|
+
target_schema_version: row[:target_schema_version],
|
163
|
+
zoekt_node_id: row[:zoekt_node_id]
|
164
|
+
)
|
165
|
+
end
|
166
|
+
|
92
167
|
def write_to(target)
|
93
168
|
target.write(@metrics.to_s)
|
94
169
|
end
|
data/lib/gitlab_exporter/git.rb
CHANGED
@@ -101,10 +101,10 @@ module GitLab
|
|
101
101
|
|
102
102
|
Utils.pgrep("^git ").each do |pid|
|
103
103
|
process_cmd = begin
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
104
|
+
File.read("/proc/#{pid}/cmdline")
|
105
|
+
rescue StandardError
|
106
|
+
"" # Process file is gone (race condition)
|
107
|
+
end
|
108
108
|
subcommand = self.class.extract_subcommand(process_cmd)
|
109
109
|
next unless subcommand # Unlikely, but just to be safe
|
110
110
|
|
@@ -142,7 +142,7 @@ module GitLab
|
|
142
142
|
|
143
143
|
cmd_splitted.shift # Because it's "git"
|
144
144
|
cmd_splitted.shift while cmd_splitted.first &&
|
145
|
-
(cmd_splitted.first.empty? || cmd_splitted.first !~ /^[^-][a-z
|
145
|
+
(cmd_splitted.first.empty? || cmd_splitted.first !~ /^[^-][a-z-]*$/)
|
146
146
|
|
147
147
|
cmd_splitted[0]
|
148
148
|
end
|
@@ -27,23 +27,9 @@ module GitLab
|
|
27
27
|
class Mapping
|
28
28
|
FIELDS = %w[size rss shared_clean shared_dirty private_clean private_dirty swap pss].freeze
|
29
29
|
|
30
|
-
attr_reader :address_start
|
31
|
-
attr_reader :address_end
|
32
|
-
attr_reader :perms
|
33
|
-
attr_reader :offset
|
34
|
-
attr_reader :device_major
|
35
|
-
attr_reader :device_minor
|
36
|
-
attr_reader :inode
|
37
|
-
attr_reader :region
|
30
|
+
attr_reader :address_start, :address_end, :perms, :offset, :device_major, :device_minor, :inode, :region
|
38
31
|
|
39
|
-
attr_accessor :size
|
40
|
-
attr_accessor :rss
|
41
|
-
attr_accessor :shared_clean
|
42
|
-
attr_accessor :shared_dirty
|
43
|
-
attr_accessor :private_dirty
|
44
|
-
attr_accessor :private_clean
|
45
|
-
attr_accessor :swap
|
46
|
-
attr_accessor :pss
|
32
|
+
attr_accessor :size, :rss, :shared_clean, :shared_dirty, :private_dirty, :private_clean, :swap, :pss
|
47
33
|
|
48
34
|
def initialize(lines)
|
49
35
|
FIELDS.each do |field|
|
@@ -11,7 +11,7 @@ module GitLab
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def probe_all
|
14
|
-
@prober_opts.
|
14
|
+
@prober_opts.each_value do |params|
|
15
15
|
Utils.wrap_in_array(params[:opts]).each do |opts|
|
16
16
|
prober = params[:class].new(metrics: @metrics, logger: @logger, **opts)
|
17
17
|
params[:methods].each do |meth|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Contains helper methods to generate TLS related configuration for web servers
|
2
2
|
module TLSHelper
|
3
|
-
CERT_REGEX = /-----BEGIN CERTIFICATE-----(?:.|\n)+?-----END CERTIFICATE
|
3
|
+
CERT_REGEX = /-----BEGIN CERTIFICATE-----(?:.|\n)+?-----END CERTIFICATE-----/
|
4
4
|
|
5
5
|
def validate_tls_config(config)
|
6
6
|
%i[tls_cert_path tls_key_path].each do |key|
|
data/spec/database/bloat_spec.rb
CHANGED
@@ -43,10 +43,10 @@ describe GitLab::Exporter::Database::BloatProber do
|
|
43
43
|
end
|
44
44
|
|
45
45
|
describe "#probe_db" do
|
46
|
-
subject { described_class.new(metrics: metrics, collector: collector, logger:
|
46
|
+
subject { described_class.new(metrics: metrics, collector: collector, logger: $stdout, **opts).probe_db }
|
47
47
|
|
48
48
|
before do
|
49
|
-
expect(collector).to receive(:logger=).with(
|
49
|
+
expect(collector).to receive(:logger=).with($stdout)
|
50
50
|
end
|
51
51
|
|
52
52
|
it "invokes the collector for each bloat type" do
|
@@ -3,9 +3,9 @@ require "gitlab_exporter/database/row_count"
|
|
3
3
|
|
4
4
|
describe GitLab::Exporter::Database::RowCountCollector do
|
5
5
|
let(:query) {
|
6
|
-
{
|
7
|
-
|
8
|
-
|
6
|
+
{ project1: { select: :projects, where: "id=1" },
|
7
|
+
project2: { select: :projects, where: "id=2" },
|
8
|
+
project3: { select: :projects, fields: { is_public: { definition: "visibility_level == 20" } } } }
|
9
9
|
}
|
10
10
|
let(:collector) { described_class.new(connection_string: "host=localhost") }
|
11
11
|
|
@@ -26,29 +26,29 @@ describe GitLab::Exporter::Database::RowCountCollector do
|
|
26
26
|
|
27
27
|
it "executes all the queries" do
|
28
28
|
expect(collector.run).to eq(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
project1: [{ count: 0, labels: {} }],
|
30
|
+
project2: [{ count: 6, labels: {} }],
|
31
|
+
project3: [{ count: 3, labels: { is_public: true } },
|
32
|
+
{ count: 6, labels: { is_public: false } }]
|
33
33
|
)
|
34
34
|
end
|
35
35
|
|
36
36
|
context "when selected_queries is passed" do
|
37
|
-
let(:collector) { described_class.new(connection_string: "host=localhost", selected_queries: ["
|
37
|
+
let(:collector) { described_class.new(connection_string: "host=localhost", selected_queries: ["project2"]) }
|
38
38
|
|
39
39
|
it "executes the selected queries" do
|
40
|
-
expect(collector.run).to eq(
|
40
|
+
expect(collector.run).to eq(project2: [{ count: 6, labels: {} }])
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
45
|
describe "#construct_query" do
|
46
46
|
it "accepts a table and where clause" do
|
47
|
-
expect(collector.send(:construct_query, query[:
|
47
|
+
expect(collector.send(:construct_query, query[:project1])).to eq "SELECT COUNT(*) FROM projects WHERE id=1;"
|
48
48
|
end
|
49
49
|
|
50
50
|
it "accepts a table and group (field) clause" do
|
51
|
-
expect(collector.send(:construct_query, query[:
|
51
|
+
expect(collector.send(:construct_query, query[:project3])).to eq \
|
52
52
|
"SELECT COUNT(*), (visibility_level == 20) AS is_public FROM projects GROUP BY is_public;"
|
53
53
|
end
|
54
54
|
end
|
data/spec/database/zoekt_spec.rb
CHANGED
@@ -4,8 +4,13 @@ require "gitlab_exporter/database/zoekt"
|
|
4
4
|
describe GitLab::Exporter::Database::ZoektCollector do
|
5
5
|
let(:connection_pool) { double("connection pool") }
|
6
6
|
let(:connection) { double("connection") }
|
7
|
-
let(:
|
7
|
+
let(:zoekt_tasks_processing_query) { described_class::ZOEKT_TASKS_PROCESSING_QUERY }
|
8
|
+
let(:zoekt_nodes_query) { described_class::ZOEKT_NODES_QUERY }
|
9
|
+
let(:zoekt_nodes_query_results) { [{ "id" => "1", "schema_version" => "2302" }] }
|
8
10
|
let(:zoekt_enabled_query) { described_class::ZOEKT_ENABLED_QUERY }
|
11
|
+
let(:zoekt_repository_schema_version_query) { described_class::ZOEKT_REPOSITORY_SCHEMA_VERSION_QUERY }
|
12
|
+
|
13
|
+
let(:zoekt_repository_schema_version_query_results) { [{ "count" => "1" }] }
|
9
14
|
|
10
15
|
subject(:collector) { described_class.new(connection_string: "host=localhost") }
|
11
16
|
|
@@ -26,13 +31,24 @@ describe GitLab::Exporter::Database::ZoektCollector do
|
|
26
31
|
describe "#run" do
|
27
32
|
let(:zoekt_enabled_results) {}
|
28
33
|
let(:frozen_time) { Time.new(2023, 1, 1, 0, 0, 0, 0) }
|
29
|
-
let(:
|
34
|
+
let(:zoekt_tasks_processing_query_results) do
|
30
35
|
[
|
31
36
|
{ "node_id" => "1", "node_name" => "zoekt-1", "task_count" => "5" },
|
32
37
|
{ "node_id" => "2", "node_name" => "zoekt-2", "task_count" => "10" }
|
33
38
|
]
|
34
39
|
end
|
35
40
|
|
41
|
+
let(:zoekt_repositories_schema_version_query_results) do
|
42
|
+
Set.new([{ target_schema_version: "2302", zoekt_node_id: "1", unfinished_repository_count: 1 }])
|
43
|
+
end
|
44
|
+
|
45
|
+
let(:result) do
|
46
|
+
{
|
47
|
+
repositories_schema_version_query_result: zoekt_repositories_schema_version_query_results,
|
48
|
+
task_processing_query_result: zoekt_tasks_processing_query_results
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
36
52
|
before do
|
37
53
|
allow(Time).to receive(:now).and_return(frozen_time)
|
38
54
|
end
|
@@ -42,10 +58,8 @@ describe GitLab::Exporter::Database::ZoektCollector do
|
|
42
58
|
stub_zoekt_not_enabled
|
43
59
|
end
|
44
60
|
|
45
|
-
it "returns
|
46
|
-
|
47
|
-
|
48
|
-
expect(collector.run).to be_nil
|
61
|
+
it "returns {}" do
|
62
|
+
expect(collector.run).to eq({})
|
49
63
|
end
|
50
64
|
end
|
51
65
|
|
@@ -54,25 +68,38 @@ describe GitLab::Exporter::Database::ZoektCollector do
|
|
54
68
|
stub_zoekt_enabled
|
55
69
|
end
|
56
70
|
|
57
|
-
it "executes the query with
|
58
|
-
expect(connection).to receive(:exec_params).with(
|
71
|
+
it "executes the query with correct params" do
|
72
|
+
expect(connection).to receive(:exec_params).with(zoekt_tasks_processing_query, [frozen_time])
|
73
|
+
.and_return(zoekt_tasks_processing_query_results)
|
74
|
+
expect(connection).to receive(:exec_params).with(zoekt_nodes_query, [])
|
75
|
+
.and_return(zoekt_nodes_query_results)
|
76
|
+
expect(connection).to receive(:exec_params).with(zoekt_repository_schema_version_query, %w[1 2302])
|
77
|
+
.and_return(zoekt_repository_schema_version_query_results)
|
59
78
|
|
60
|
-
expect(collector.run).to eq(
|
79
|
+
expect(collector.run).to eq(result)
|
61
80
|
end
|
62
81
|
|
63
82
|
context "when PG::UndefinedTable is raised" do
|
64
|
-
it "
|
65
|
-
allow(connection).to receive(:exec_params).with(
|
83
|
+
it "does not includes the key which got the exception" do
|
84
|
+
allow(connection).to receive(:exec_params).with(zoekt_tasks_processing_query, [frozen_time])
|
85
|
+
.and_raise(PG::UndefinedTable)
|
86
|
+
allow(connection).to receive(:exec_params).with(zoekt_nodes_query, [])
|
87
|
+
.and_raise(PG::UndefinedTable)
|
66
88
|
|
67
|
-
expect(collector.run).to
|
89
|
+
expect(collector.run).to eq({})
|
68
90
|
end
|
69
91
|
end
|
70
92
|
|
71
93
|
context "when PG::UndefinedColumn is raised" do
|
72
|
-
it "
|
73
|
-
allow(connection).to receive(:exec_params).with(
|
74
|
-
|
75
|
-
expect(
|
94
|
+
it "does not includes the key which got the exception" do
|
95
|
+
allow(connection).to receive(:exec_params).with(zoekt_tasks_processing_query, [frozen_time])
|
96
|
+
.and_return(zoekt_tasks_processing_query_results)
|
97
|
+
expect(connection).to receive(:exec_params).with(zoekt_nodes_query, [])
|
98
|
+
.and_return(zoekt_nodes_query_results)
|
99
|
+
expect(connection).to receive(:exec_params).with(zoekt_repository_schema_version_query, %w[1 2302])
|
100
|
+
.and_raise(PG::UndefinedTable)
|
101
|
+
|
102
|
+
expect(collector.run).to eq({ task_processing_query_result: zoekt_tasks_processing_query_results })
|
76
103
|
end
|
77
104
|
end
|
78
105
|
end
|
@@ -99,10 +126,15 @@ describe GitLab::Exporter::Database::ZoektProber do
|
|
99
126
|
let(:metrics) { double("PrometheusMetrics", add: nil) }
|
100
127
|
let(:collector) { double(GitLab::Exporter::Database::ZoektCollector, run: data) }
|
101
128
|
let(:data) do
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
129
|
+
{
|
130
|
+
repositories_schema_version_query_result: Set.new(
|
131
|
+
[{ target_schema_version: "2302", zoekt_node_id: "1", unfinished_repository_count: 1 }]
|
132
|
+
),
|
133
|
+
task_processing_query_result: [
|
134
|
+
{ "node_id" => "1", "node_name" => "zoekt-1", "task_count" => "5" },
|
135
|
+
{ "node_id" => "2", "node_name" => "zoekt-2", "task_count" => "10" }
|
136
|
+
]
|
137
|
+
}
|
106
138
|
end
|
107
139
|
|
108
140
|
describe "#probe_db" do
|
@@ -123,7 +155,7 @@ describe GitLab::Exporter::Database::ZoektProber do
|
|
123
155
|
it "adds metrics for each node" do
|
124
156
|
expect(collector).to receive(:run).and_return(data)
|
125
157
|
|
126
|
-
data.each do |node_data|
|
158
|
+
data[:task_processing_query_result].each do |node_data|
|
127
159
|
expect(metrics).to receive(:add)
|
128
160
|
.with("search_zoekt_task_processing_queue_size",
|
129
161
|
node_data["task_count"].to_i,
|
@@ -131,6 +163,16 @@ describe GitLab::Exporter::Database::ZoektProber do
|
|
131
163
|
node_id: node_data["node_id"])
|
132
164
|
end
|
133
165
|
|
166
|
+
data[:repositories_schema_version_query_result].each do |node_data|
|
167
|
+
expect(metrics).to receive(:add)
|
168
|
+
.with(
|
169
|
+
"search_zoekt_repositories_schema_version_count",
|
170
|
+
node_data[:unfinished_repository_count].to_i,
|
171
|
+
target_schema_version: node_data[:target_schema_version],
|
172
|
+
zoekt_node_id: node_data[:zoekt_node_id]
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
134
176
|
probe_db
|
135
177
|
end
|
136
178
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitlab-exporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 16.
|
4
|
+
version: 16.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pablo Carranza
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.5.
|
19
|
+
version: 2.5.4
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.5.
|
26
|
+
version: 2.5.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: deep_merge
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,42 +44,42 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - '='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 2.
|
47
|
+
version: 2.14.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 2.
|
54
|
+
version: 2.14.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: pg
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - '='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 1.
|
61
|
+
version: 1.6.2
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - '='
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 1.
|
68
|
+
version: 1.6.2
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: puma
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - '='
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 6.6.
|
75
|
+
version: 6.6.1
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - '='
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 6.6.
|
82
|
+
version: 6.6.1
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: quantile
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,28 +100,28 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - '='
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 4.
|
103
|
+
version: 4.8.1
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - '='
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 4.
|
110
|
+
version: 4.8.1
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: redis-namespace
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - '='
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 1.
|
117
|
+
version: 1.11.0
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - '='
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 1.
|
124
|
+
version: 1.11.0
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: sidekiq
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|