specbandit 1.0.1 → 1.1.1
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/lib/specbandit/cli.rb +4 -0
- data/lib/specbandit/configuration.rb +20 -1
- data/lib/specbandit/redis_queue.rb +22 -6
- data/lib/specbandit/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 70efc56f9de13cd1e141cbb1ad39ff22cf1a07cdfbcd2c1257cefc55f5cb73fe
|
|
4
|
+
data.tar.gz: 6070e8b72aec64162a3e37190e787abbd23bf464faf74d06212e401c7c312fed
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c7fc604a65cba2387b1177fef33ad2994e13677777d6d87b53f68aa29a00616c864dc874b5571947c4e837d0c3e25b24cc4d99d0841c94b79433258e8f5faba7
|
|
7
|
+
data.tar.gz: 7c6acd6833e1f082e2c764de7d32ab67407726d6905cc6246cbbe0921410f2ad3db4a503ee5932240414ebf413538830db54e8275adb4cd6c1f3d9bc71a195e4
|
data/lib/specbandit/cli.rb
CHANGED
|
@@ -131,6 +131,10 @@ module Specbandit
|
|
|
131
131
|
Specbandit.configuration.report = v
|
|
132
132
|
end
|
|
133
133
|
|
|
134
|
+
opts.on('--redis-max-attempts N', Integer, 'Redis connection retry attempts (default: 5)') do |v|
|
|
135
|
+
Specbandit.configuration.redis_max_attempts = v
|
|
136
|
+
end
|
|
137
|
+
|
|
134
138
|
opts.on('--verbose', 'Show per-batch file list and full command output (default: quiet)') do
|
|
135
139
|
Specbandit.configuration.verbose = true
|
|
136
140
|
end
|
|
@@ -5,7 +5,9 @@ module Specbandit
|
|
|
5
5
|
attr_accessor :redis_url, :batch_size, :key, :rspec_opts, :key_ttl,
|
|
6
6
|
:key_rerun, :verbose,
|
|
7
7
|
:adapter, :command, :command_opts,
|
|
8
|
-
:key_failed, :report
|
|
8
|
+
:key_failed, :report,
|
|
9
|
+
:redis_max_attempts, :redis_connect_timeout, :redis_timeout,
|
|
10
|
+
:redis_reconnect_attempts
|
|
9
11
|
|
|
10
12
|
DEFAULT_REDIS_URL = 'redis://localhost:6379'
|
|
11
13
|
DEFAULT_BATCH_SIZE = 5
|
|
@@ -16,6 +18,17 @@ module Specbandit
|
|
|
16
18
|
DEFAULT_KEY_TTL = 604_800 # 1 week in seconds
|
|
17
19
|
DEFAULT_ADAPTER = 'cli'
|
|
18
20
|
|
|
21
|
+
# Redis connection resilience. Redis is a best-effort coordination store for
|
|
22
|
+
# a distributed test run, and CI runners can sit a WAN hop away from it
|
|
23
|
+
# (e.g. cross-datacenter mesh), so a transient blip must not red the build.
|
|
24
|
+
# We retry a handful of times with capped exponential backoff, and give the
|
|
25
|
+
# underlying client explicit connect/read/write timeouts + reconnects rather
|
|
26
|
+
# than relying on library defaults.
|
|
27
|
+
DEFAULT_REDIS_MAX_ATTEMPTS = 5
|
|
28
|
+
DEFAULT_REDIS_CONNECT_TIMEOUT = 3.0
|
|
29
|
+
DEFAULT_REDIS_TIMEOUT = 5.0
|
|
30
|
+
DEFAULT_REDIS_RECONNECT_ATTEMPTS = 3
|
|
31
|
+
|
|
19
32
|
def initialize
|
|
20
33
|
@redis_url = ENV.fetch('SPECBANDIT_REDIS_URL', DEFAULT_REDIS_URL)
|
|
21
34
|
@batch_size = Integer(ENV.fetch('SPECBANDIT_BATCH_SIZE', DEFAULT_BATCH_SIZE))
|
|
@@ -29,12 +42,18 @@ module Specbandit
|
|
|
29
42
|
@command_opts = parse_space_separated(ENV.fetch('SPECBANDIT_COMMAND_OPTS', nil))
|
|
30
43
|
@key_failed = ENV.fetch('SPECBANDIT_KEY_FAILED', nil)
|
|
31
44
|
@report = ENV.fetch('SPECBANDIT_REPORT', nil)
|
|
45
|
+
|
|
46
|
+
@redis_max_attempts = Integer(ENV.fetch('SPECBANDIT_REDIS_MAX_ATTEMPTS', DEFAULT_REDIS_MAX_ATTEMPTS))
|
|
47
|
+
@redis_connect_timeout = Float(ENV.fetch('SPECBANDIT_REDIS_CONNECT_TIMEOUT', DEFAULT_REDIS_CONNECT_TIMEOUT))
|
|
48
|
+
@redis_timeout = Float(ENV.fetch('SPECBANDIT_REDIS_TIMEOUT', DEFAULT_REDIS_TIMEOUT))
|
|
49
|
+
@redis_reconnect_attempts = Integer(ENV.fetch('SPECBANDIT_REDIS_RECONNECT_ATTEMPTS', DEFAULT_REDIS_RECONNECT_ATTEMPTS))
|
|
32
50
|
end
|
|
33
51
|
|
|
34
52
|
def validate!
|
|
35
53
|
raise Error, 'key is required (set via --key or SPECBANDIT_KEY)' if key.nil? || key.empty?
|
|
36
54
|
raise Error, 'batch_size must be a positive integer' unless batch_size.positive?
|
|
37
55
|
raise Error, 'key_ttl must be a positive integer' unless key_ttl.positive?
|
|
56
|
+
raise Error, 'redis_max_attempts must be a positive integer' unless redis_max_attempts.positive?
|
|
38
57
|
end
|
|
39
58
|
|
|
40
59
|
private
|
|
@@ -6,12 +6,28 @@ module Specbandit
|
|
|
6
6
|
class RedisQueue
|
|
7
7
|
attr_reader :redis
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
# Cap the exponential backoff so a real outage degrades/fails within a
|
|
10
|
+
# bounded window instead of sleeping for minutes on the last attempts.
|
|
11
|
+
MAX_BACKOFF_SECONDS = 10
|
|
12
|
+
|
|
13
|
+
def initialize(
|
|
14
|
+
redis_url: Specbandit.configuration.redis_url,
|
|
15
|
+
connect_timeout: Specbandit.configuration.redis_connect_timeout,
|
|
16
|
+
read_timeout: Specbandit.configuration.redis_timeout,
|
|
17
|
+
write_timeout: Specbandit.configuration.redis_timeout,
|
|
18
|
+
reconnect_attempts: Specbandit.configuration.redis_reconnect_attempts,
|
|
19
|
+
max_attempts: Specbandit.configuration.redis_max_attempts
|
|
20
|
+
)
|
|
21
|
+
@max_attempts = max_attempts
|
|
22
|
+
@redis = Redis.new(
|
|
23
|
+
url: redis_url,
|
|
24
|
+
connect_timeout: connect_timeout,
|
|
25
|
+
read_timeout: read_timeout,
|
|
26
|
+
write_timeout: write_timeout,
|
|
27
|
+
reconnect_attempts: reconnect_attempts
|
|
28
|
+
)
|
|
11
29
|
end
|
|
12
30
|
|
|
13
|
-
MAX_ATTEMPTS = 3
|
|
14
|
-
|
|
15
31
|
# Push file paths onto the queue and set an expiry on the key.
|
|
16
32
|
# Returns the new length of the list.
|
|
17
33
|
def push(key, files, ttl: nil)
|
|
@@ -83,7 +99,7 @@ module Specbandit
|
|
|
83
99
|
"#{key}:published"
|
|
84
100
|
end
|
|
85
101
|
|
|
86
|
-
def with_retries(attempts:
|
|
102
|
+
def with_retries(attempts: @max_attempts)
|
|
87
103
|
retries = 0
|
|
88
104
|
begin
|
|
89
105
|
yield
|
|
@@ -91,7 +107,7 @@ module Specbandit
|
|
|
91
107
|
retries += 1
|
|
92
108
|
raise if retries >= attempts
|
|
93
109
|
|
|
94
|
-
delay = 2**retries
|
|
110
|
+
delay = [2**retries, MAX_BACKOFF_SECONDS].min
|
|
95
111
|
warn "[specbandit] Redis connection failed (attempt #{retries}/#{attempts}): #{e.message}. Retrying in #{delay}s..."
|
|
96
112
|
sleep(delay)
|
|
97
113
|
retry
|
data/lib/specbandit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: specbandit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ferran Basora
|
|
@@ -109,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: '0'
|
|
111
111
|
requirements: []
|
|
112
|
-
rubygems_version: 4.0.
|
|
112
|
+
rubygems_version: 4.0.16
|
|
113
113
|
specification_version: 4
|
|
114
114
|
summary: Distributed test runner using Redis as a work queue
|
|
115
115
|
test_files: []
|