Skip to content

Commit 504db35

Browse files
authored
Merge pull request #184 from DougEdey/add_ttl
Add support for a custom TTL of Redis keys for Minitest, defaulting to 8 hours
2 parents b006aaf + 955fdc7 commit 504db35

File tree

10 files changed

+58
-2
lines changed

10 files changed

+58
-2
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ Two implementations are provided, please refer to the respective documentations:
3737
- [Python](python/)
3838
- [Ruby](ruby/)
3939

40+
## Redis Requirements
41+
42+
`ci-queue` expects the Redis server to have an [eviction policy](https://redis.io/docs/manual/eviction/#eviction-policies) of `allkeys-lru`.
43+
4044
## Contributing
4145

4246
Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/ci-queue.

ruby/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,9 @@ rspec-queue --queue redis://example.com --timeout 600 --report
7070
#### Limitations
7171

7272
Because of how `ci-queue` executes the examples, `before(:all)` and `after(:all)` hooks are not supported. `rspec-queue` will explicitly reject them.
73+
74+
## Custom Redis Expiry
75+
76+
`ci-queue` expects the Redis server to have an [eviction policy](https://redis.io/docs/manual/eviction/#eviction-policies) of `allkeys-lru`.
77+
78+
You can also use `--redis-ttl` to set a custom expiration time for all CI Queue keys, this defaults to 8 hours (28,800 seconds)

ruby/lib/ci/queue/configuration.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class Configuration
55
attr_accessor :timeout, :worker_id, :max_requeues, :grind_count, :failure_file
66
attr_accessor :requeue_tolerance, :namespace, :failing_test, :statsd_endpoint
77
attr_accessor :max_test_duration, :max_test_duration_percentile, :track_test_duration
8-
attr_accessor :max_test_failed
8+
attr_accessor :max_test_failed, :redis_ttl
99
attr_reader :circuit_breakers
1010
attr_writer :seed, :build_id
1111
attr_writer :queue_init_timeout
@@ -18,6 +18,7 @@ def from_env(env)
1818
seed: env['CIRCLE_SHA1'] || env['BUILDKITE_COMMIT'] || env['TRAVIS_COMMIT'] || env['HEROKU_TEST_RUN_COMMIT_VERSION'] || env['SEMAPHORE_GIT_SHA'],
1919
flaky_tests: load_flaky_tests(env['CI_QUEUE_FLAKY_TESTS']),
2020
statsd_endpoint: env['CI_QUEUE_STATSD_ADDR'],
21+
redis_ttl: env['CI_QUEUE_REDIS_TTL']&.to_i || 8 * 60 * 60,
2122
)
2223
end
2324

@@ -34,7 +35,7 @@ def initialize(
3435
namespace: nil, seed: nil, flaky_tests: [], statsd_endpoint: nil, max_consecutive_failures: nil,
3536
grind_count: nil, max_duration: nil, failure_file: nil, max_test_duration: nil,
3637
max_test_duration_percentile: 0.5, track_test_duration: false, max_test_failed: nil,
37-
queue_init_timeout: nil
38+
queue_init_timeout: nil, redis_ttl: 8 * 60 * 60
3839
)
3940
@build_id = build_id
4041
@circuit_breakers = [CircuitBreaker::Disabled]
@@ -55,6 +56,7 @@ def initialize(
5556
@worker_id = worker_id
5657
self.max_consecutive_failures = max_consecutive_failures
5758
self.max_duration = max_duration
59+
@redis_ttl = redis_ttl
5860
end
5961

6062
def queue_init_timeout

ruby/lib/ci/queue/redis/build_record.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def record_error(id, payload, stats: nil)
4141
id.dup.force_encoding(Encoding::BINARY),
4242
payload.dup.force_encoding(Encoding::BINARY),
4343
)
44+
pipeline.expire(key('error-reports'), config.redis_ttl)
4445
record_stats(stats, pipeline: pipeline)
4546
end
4647
nil
@@ -90,6 +91,7 @@ def record_stats(stats, pipeline: redis)
9091
return unless stats
9192
stats.each do |stat_name, stat_value|
9293
pipeline.hset(key(stat_name), config.worker_id, stat_value)
94+
pipeline.expire(key(stat-name), config.redis_ttl)
9395
end
9496
end
9597

ruby/lib/ci/queue/redis/grind_record.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def record_error(payload, stats: nil)
1616
key('error-reports'),
1717
payload.force_encoding(Encoding::BINARY),
1818
)
19+
pipeline.expire(key('error-reports'), config.redis_ttl)
1920
record_stats(stats, pipeline: pipeline)
2021
end
2122
nil
@@ -58,6 +59,7 @@ def record_stats(stats, pipeline: redis)
5859
return unless stats
5960
stats.each do |stat_name, stat_value|
6061
pipeline.hset(key(stat_name), config.worker_id, stat_value)
62+
pipeline.expire(key(stat_name), config.redis_ttl)
6163
end
6264
end
6365
end

ruby/lib/ci/queue/redis/test_time_record.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def record_test_time(test_name, duration)
2424
test_time_key(test_name),
2525
duration.to_s.force_encoding(Encoding::BINARY),
2626
)
27+
pipeline.expire(test_time_key(test_name), config.redis_ttl)
2728
end
2829
nil
2930
end
@@ -34,6 +35,7 @@ def record_test_name(test_name)
3435
all_test_names_key,
3536
test_name.dup.force_encoding(Encoding::BINARY),
3637
)
38+
pipeline.expire(all_test_names_key, config.redis_ttl)
3739
end
3840
nil
3941
end

ruby/lib/ci/queue/redis/worker.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ def poll
5353
sleep 0.05
5454
end
5555
end
56+
redis.pipelined do |pipeline|
57+
pipeline.expire(key('worker', worker_id, 'queue'), config.redis_ttl)
58+
pipeline.expire(key('processed'), config.redis_ttl)
59+
end
5660
rescue *CONNECTION_ERRORS
5761
end
5862

@@ -198,9 +202,14 @@ def push(tests)
198202
transaction.lpush(key('queue'), tests) unless tests.empty?
199203
transaction.set(key('total'), @total)
200204
transaction.set(key('master-status'), 'ready')
205+
206+
transaction.expire(key('queue'), config.redis_ttl)
207+
transaction.expire(key('total'), config.redis_ttl)
208+
transaction.expire(key('master-status'), config.redis_ttl)
201209
end
202210
end
203211
register
212+
redis.expire(key('workers'), config.redis_ttl)
204213
rescue *CONNECTION_ERRORS
205214
raise if @master
206215
end

ruby/lib/minitest/queue/runner.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,14 @@ def parser
487487
end
488488
end
489489

490+
help = <<~EOS
491+
Defines how long the test report remain after the test run, in seconds.
492+
Defaults to 28,800 (8 hours)
493+
EOS
494+
opts.on("--redis-ttl SECONDS", Integer, help) do |time|
495+
queue.config.redis_ttl = time
496+
end
497+
490498
opts.separator ""
491499
opts.separator " retry: Replays a previous run in the same order."
492500

ruby/lib/rspec/queue.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,15 @@ def parser(options)
157157
queue_config.max_consecutive_failures = Integer(max)
158158
end
159159

160+
help = <<~EOS
161+
Defines how long the test report remain after the test run, in seconds.
162+
Defaults to 28,800 (8 hours)
163+
EOS
164+
parsed.separator ""
165+
parser.on("--redis-ttl SECONDS", Integer, help) do |time|
166+
queue.config.redis_ttl = time
167+
end
168+
160169
parser
161170
end
162171

ruby/test/ci/queue/configuration_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ def test_namespace
6565
assert_equal 'browser:9e08ef3c-d6e6-4a86-91dd-577ce5205b8e', config.build_id
6666
end
6767

68+
def test_redis_ttl_defaults
69+
config = Configuration.new
70+
assert_equal(28_800, config.redis_ttl)
71+
end
72+
73+
def test_redis_ttl_from_env
74+
config = Configuration.from_env(
75+
"CI_QUEUE_REDIS_TTL" => "14400"
76+
)
77+
assert_equal(14_400, config.redis_ttl)
78+
end
79+
6880
def test_parses_file_correctly
6981
Tempfile.open('flaky_test_file') do |file|
7082
file.write(SharedTestCases::TEST_NAMES.join("\n") + "\n")

0 commit comments

Comments
 (0)