unleash 0.1.4 → 0.1.5
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/.gitignore +3 -0
- data/.travis.yml +5 -2
- data/README.md +37 -8
- data/TODO.md +5 -5
- data/lib/unleash/client.rb +18 -9
- data/lib/unleash/configuration.rb +5 -1
- data/lib/unleash/context.rb +26 -5
- data/lib/unleash/feature_toggle.rb +7 -5
- data/lib/unleash/scheduled_executor.rb +5 -1
- data/lib/unleash/strategy/gradual_rollout_sessionid.rb +1 -0
- data/lib/unleash/strategy/gradual_rollout_userid.rb +1 -0
- data/lib/unleash/version.rb +1 -1
- data/unleash-client.gemspec +4 -3
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d8661e45cf753ab1c4ffdda0c4445657237cf0dafb26c1f701e258a3fe8c28f
|
4
|
+
data.tar.gz: 440ddb7d149983453cbda346264e12510fb97a3372ac99bcb5e5e8d60e25df7d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d913c18a4dc0894b19a6281dfb6112891bcb296725afd75aa84172fc7849b36c87962f55151094820d0951c0ea5ec2dd4c8e0e9ce946cc99e2747c9b41e94472
|
7
|
+
data.tar.gz: bcd865ead7231ea7dbc24b3318498ccbddaab5a7032375c8d25f603952b094141126ebae8e0cf668e74d7ba9e6c73be27f083175211529714967e941d0744521
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
- 2.2
|
5
4
|
- 2.3
|
6
5
|
- 2.4
|
7
6
|
- 2.5
|
7
|
+
- 2.6
|
8
8
|
- jruby
|
9
|
-
before_install:
|
9
|
+
before_install:
|
10
|
+
- gem install bundler -v 2.0.1
|
11
|
+
# install client spec from official repository:
|
12
|
+
- git clone --depth 5 https://github.com/Unleash/client-specification.git client-specification
|
data/README.md
CHANGED
@@ -12,7 +12,7 @@ Leverage the [Unleash Server](https://github.com/Unleash/unleash) for powerful f
|
|
12
12
|
Add this line to your application's Gemfile:
|
13
13
|
|
14
14
|
```ruby
|
15
|
-
gem 'unleash', '~> 0.1.
|
15
|
+
gem 'unleash', '~> 0.1.5'
|
16
16
|
```
|
17
17
|
|
18
18
|
And then execute:
|
@@ -25,16 +25,15 @@ Or install it yourself as:
|
|
25
25
|
|
26
26
|
## Configure
|
27
27
|
|
28
|
-
It is **required** to configure the `url` of the unleash server. Please substitute the sample `'http://unleash.herokuapp.com/api'` for the url of your own instance.
|
28
|
+
It is **required** to configure the `url` of the unleash server and `app_name` with the name of the runninng application. Please substitute the sample `'http://unleash.herokuapp.com/api'` for the url of your own instance.
|
29
29
|
|
30
|
-
It is **highly recommended** to configure `
|
30
|
+
It is **highly recommended** to configure the `instance_id` parameter as well.
|
31
31
|
|
32
|
-
For other options please see `lib/unleash/configuration.rb`.
|
33
32
|
|
34
33
|
```ruby
|
35
34
|
Unleash.configure do |config|
|
36
|
-
config.url
|
37
|
-
config.app_name
|
35
|
+
config.url = 'http://unleash.herokuapp.com/api'
|
36
|
+
config.app_name = 'my_ruby_app'
|
38
37
|
end
|
39
38
|
```
|
40
39
|
|
@@ -44,6 +43,27 @@ or instantiate the client with the valid configuration:
|
|
44
43
|
UNLEASH = Unleash::Client.new(url: 'http://unleash.herokuapp.com/api', app_name: 'my_ruby_app')
|
45
44
|
```
|
46
45
|
|
46
|
+
#### List of Arguments
|
47
|
+
|
48
|
+
Argument | Description | Required? | Type | Default Value|
|
49
|
+
---------|-------------|-----------|-------|---------------|
|
50
|
+
`url` | Unleash server URL. | Y | String | N/A |
|
51
|
+
`app_name` | Name of your program. | Y | String | N/A |
|
52
|
+
`instance_id` | Identifier for the running instance of program. Important so you can trace back to where metrics are being collected from. **Highly recommended be be set.** | N | String | random UUID |
|
53
|
+
`refresh_interval` | How often the unleash client should check with the server for configuration changes. | N | Integer | 15 |
|
54
|
+
`metrics_interval` | How often the unleash client should send metrics to server. | N | Integer | 10 |
|
55
|
+
`disable_client` | Disables all communication with the Unleash server. If set, `is_enabled?` will always answer with the `default_value` and configuration validation is skipped. Defeats the entire purpose of using unleash, but can be useful in when running tests. | N | Boolean | F |
|
56
|
+
`disable_metrics` | Disables sending metrics to Unleash server. | N | Boolean | F |
|
57
|
+
`custom_http_headers` | Custom headers to send to Unleash. | N | Hash | {} |
|
58
|
+
`timeout` | How long to wait for the connection to be established or wait in reading state (open_timeout/read_timeout) | N | Integer | 30 |
|
59
|
+
`retry_limit` | How many consecutive failures in connecting to the Unleash server are allowed before giving up. | N | Integer | 1 |
|
60
|
+
`backup_file` | Filename to store the last known state from the Unleash server. Best to not change this from the default. | N | `Dir.tmpdir + "/unleash-#{app_name}-repo.json` |
|
61
|
+
`logger` | Specify a custom `Logger` class to handle logs from the client. | N | `Logger.new(STDOUT)` |
|
62
|
+
`log_level` | Change the log level for the `Logger` class. | N | `Logger::ERROR` |
|
63
|
+
|
64
|
+
For in a more in depth look, please see `lib/unleash/configuration.rb`.
|
65
|
+
|
66
|
+
|
47
67
|
## Usage in a plain Ruby Application
|
48
68
|
|
49
69
|
```ruby
|
@@ -74,6 +94,7 @@ Unleash.configure do |config|
|
|
74
94
|
config.url = 'http://unleash.herokuapp.com/api'
|
75
95
|
config.app_name = Rails.application.class.parent.to_s
|
76
96
|
# config.instance_id = "#{Socket.gethostname}"
|
97
|
+
config.logger = Rails.logger
|
77
98
|
end
|
78
99
|
|
79
100
|
UNLEASH = Unleash::Client.new
|
@@ -139,6 +160,14 @@ if Rails.configuration.unleash.is_enabled? "AwesomeFeature", @unleash_context
|
|
139
160
|
end
|
140
161
|
```
|
141
162
|
|
163
|
+
If the feature is not found in the server, it will by default return false. However you can override that by setting the default return value to `true`:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
if UNLEASH.is_enabled? "AwesomeFeature", @unleash_context, true
|
167
|
+
puts "AwesomeFeature is enabled by default"
|
168
|
+
end
|
169
|
+
```
|
170
|
+
|
142
171
|
## Local test client
|
143
172
|
|
144
173
|
```
|
@@ -155,7 +184,7 @@ This client comes with the all the required strategies out of the box:
|
|
155
184
|
* GradualRolloutSessionIdStrategy
|
156
185
|
* GradualRolloutUserIdStrategy
|
157
186
|
* RemoteAddressStrategy
|
158
|
-
*
|
187
|
+
* UnknownStrategy
|
159
188
|
* UserWithIdStrategy
|
160
189
|
|
161
190
|
|
@@ -165,7 +194,7 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
165
194
|
|
166
195
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
167
196
|
|
168
|
-
See (TODO.md) for known limitations, and feature roadmap.
|
197
|
+
See [TODO.md](TODO.md) for known limitations, and feature roadmap.
|
169
198
|
|
170
199
|
|
171
200
|
## Contributing
|
data/TODO.md
CHANGED
@@ -6,13 +6,10 @@ The Ruby client should be pretty stable now. But no warranty is given, and some
|
|
6
6
|
|
7
7
|
Implement:
|
8
8
|
----------
|
9
|
-
*
|
9
|
+
* Document writing of custom strategies.
|
10
10
|
|
11
11
|
To test: (and write tests for)
|
12
12
|
--------
|
13
|
-
* Implement spec test for ruby client specs using https://github.com/Unleash/client-specification/blob/master/05-gradual-rollout-random-strategy.json (similar to the examples below) to ensure consistent client behaviour.
|
14
|
-
* java: https://github.com/Unleash/unleash-client-java/compare/master...integration-spec
|
15
|
-
* node: https://github.com/Unleash/unleash-client-node/compare/client-specification?expand=1
|
16
13
|
* MetricsReporter
|
17
14
|
* everything else :)
|
18
15
|
|
@@ -34,4 +31,7 @@ DONE:
|
|
34
31
|
* Switch hashing function to use murmurhash3 as per https://github.com/Unleash/unleash/issues/247
|
35
32
|
* Document usage with Rails
|
36
33
|
* Support for allowing custom strategies.
|
37
|
-
|
34
|
+
* Possibility for custom HTTP headers when interacting with unleash server.
|
35
|
+
* Implement spec test for ruby client specs using https://github.com/Unleash/client-specification/blob/master/05-gradual-rollout-random-strategy.json (similar to the examples below) to ensure consistent client behaviour.
|
36
|
+
* java: https://github.com/Unleash/unleash-client-java/compare/master...integration-spec
|
37
|
+
* node: https://github.com/Unleash/unleash-client-node/compare/client-specification?expand=1
|
data/lib/unleash/client.rb
CHANGED
@@ -15,22 +15,31 @@ module Unleash
|
|
15
15
|
Unleash.logger = Unleash.configuration.logger
|
16
16
|
Unleash.logger.level = Unleash.configuration.log_level
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
unless Unleash.configuration.disable_client
|
19
|
+
Unleash.toggle_fetcher = Unleash::ToggleFetcher.new
|
20
|
+
register
|
21
|
+
|
22
|
+
unless Unleash.configuration.disable_metrics
|
23
|
+
Unleash.toggle_metrics = Unleash::Metrics.new
|
24
|
+
Unleash.reporter = Unleash::MetricsReporter.new
|
25
|
+
scheduledExecutor = Unleash::ScheduledExecutor.new('MetricsReporter', Unleash.configuration.metrics_interval)
|
26
|
+
scheduledExecutor.run do
|
27
|
+
Unleash.reporter.send
|
28
|
+
end
|
27
29
|
end
|
30
|
+
else
|
31
|
+
Unleash.logger.warn "Unleash::Client is disabled! Will only return default results!"
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
31
35
|
def is_enabled?(feature, context = nil, default_value = false)
|
32
36
|
Unleash.logger.debug "Unleash::Client.is_enabled? feature: #{feature} with context #{context}"
|
33
37
|
|
38
|
+
if Unleash.configuration.disable_client
|
39
|
+
Unleash.logger.warn "unleash_client is disabled! Always returning #{default_value} for feature #{feature}!"
|
40
|
+
return default_value
|
41
|
+
end
|
42
|
+
|
34
43
|
toggle_as_hash = Unleash.toggles.select{ |toggle| toggle['name'] == feature }.first if Unleash.toggles
|
35
44
|
|
36
45
|
if toggle_as_hash.nil?
|
@@ -5,6 +5,7 @@ module Unleash
|
|
5
5
|
class Configuration
|
6
6
|
attr_accessor :url, :app_name, :instance_id,
|
7
7
|
:custom_http_headers,
|
8
|
+
:disable_client,
|
8
9
|
:disable_metrics, :timeout, :retry_limit,
|
9
10
|
:refresh_interval, :metrics_interval,
|
10
11
|
:backup_file, :logger, :log_level
|
@@ -19,6 +20,7 @@ module Unleash
|
|
19
20
|
else
|
20
21
|
raise ArgumentError, "custom_http_headers must be a hash."
|
21
22
|
end
|
23
|
+
self.disable_client = opts[:disable_client] || false
|
22
24
|
self.disable_metrics = opts[:disable_metrics] || false
|
23
25
|
self.refresh_interval = opts[:refresh_interval] || 15
|
24
26
|
self.metrics_interval = opts[:metrics_interval] || 10
|
@@ -28,7 +30,7 @@ module Unleash
|
|
28
30
|
self.backup_file = opts[:backup_file] || nil
|
29
31
|
|
30
32
|
self.logger = opts[:logger] || Logger.new(STDOUT)
|
31
|
-
self.log_level = opts[:log_level] || Logger::
|
33
|
+
self.log_level = opts[:log_level] || Logger::WARN
|
32
34
|
|
33
35
|
|
34
36
|
if opts[:logger].nil?
|
@@ -47,6 +49,8 @@ module Unleash
|
|
47
49
|
end
|
48
50
|
|
49
51
|
def validate!
|
52
|
+
return if self.disable_client
|
53
|
+
|
50
54
|
if self.app_name.nil? or self.url.nil?
|
51
55
|
raise ArgumentError, "URL and app_name are required parameters."
|
52
56
|
end
|
data/lib/unleash/context.rb
CHANGED
@@ -5,14 +5,35 @@ module Unleash
|
|
5
5
|
|
6
6
|
def initialize(params = {})
|
7
7
|
params_is_a_hash = params.is_a?(Hash)
|
8
|
-
self.user_id =
|
9
|
-
self.session_id =
|
10
|
-
self.remote_address =
|
11
|
-
self.properties =
|
8
|
+
self.user_id = fetch(params, 'userId')
|
9
|
+
self.session_id = fetch(params, 'sessionId')
|
10
|
+
self.remote_address = fetch(params, 'remoteAddress')
|
11
|
+
self.properties =
|
12
|
+
if params_is_a_hash && ( params.fetch(:properties, nil) || params.fetch('properties', nil) ).is_a?(Hash)
|
13
|
+
fetch(params, 'properties', {})
|
14
|
+
else
|
15
|
+
{}
|
16
|
+
end
|
12
17
|
end
|
13
18
|
|
14
19
|
def to_s
|
15
20
|
"<Context: user_id=#{self.user_id},session_id=#{self.session_id},remote_address=#{self.remote_address},properties=#{self.properties}>"
|
16
21
|
end
|
22
|
+
|
23
|
+
private
|
24
|
+
# Fetch key from hash. Try first with using camelCase, and if not found, try with snake case.
|
25
|
+
# This way we are are idiomatically compliant with ruby, but still giving priority to the same
|
26
|
+
# key names as in the other clients.
|
27
|
+
def fetch(params, camelcase_key, default_ret = '')
|
28
|
+
return default_ret unless params.is_a?(Hash)
|
29
|
+
return default_ret unless camelcase_key.is_a?(String) or camelcase_key.is_a?(Symbol)
|
30
|
+
|
31
|
+
params.fetch(camelcase_key, nil) || params.fetch(snake_sym(camelcase_key), nil) || default_ret
|
32
|
+
end
|
33
|
+
|
34
|
+
# transform CamelCase to snake_case and make it a sym, if it is a string
|
35
|
+
def snake_sym(key)
|
36
|
+
key.is_a?(String) ? key.gsub(/(.)([A-Z])/,'\1_\2').downcase.to_sym : key
|
37
|
+
end
|
17
38
|
end
|
18
|
-
end
|
39
|
+
end
|
@@ -5,10 +5,12 @@ module Unleash
|
|
5
5
|
attr_accessor :name, :enabled, :strategies, :choices, :choices_lock
|
6
6
|
|
7
7
|
def initialize(params={})
|
8
|
-
|
9
|
-
self.enabled = params['enabled'] || false
|
8
|
+
params = {} if params.nil?
|
10
9
|
|
11
|
-
self.
|
10
|
+
self.name = params.fetch('name', nil)
|
11
|
+
self.enabled = params.fetch('enabled', false)
|
12
|
+
|
13
|
+
self.strategies = params.fetch('strategies', [])
|
12
14
|
.select{|s| ( s.key?('name') && Unleash::STRATEGIES.key?(s['name'].to_sym) ) }
|
13
15
|
.map{|s| ActivationStrategy.new(s['name'], s['parameters'])} || []
|
14
16
|
|
@@ -26,12 +28,12 @@ module Unleash
|
|
26
28
|
context = nil
|
27
29
|
end
|
28
30
|
|
29
|
-
result = self.enabled && self.strategies.select{ |s|
|
31
|
+
result = self.enabled && ( self.strategies.select{ |s|
|
30
32
|
strategy = Unleash::STRATEGIES.fetch(s.name.to_sym, :unknown)
|
31
33
|
r = strategy.is_enabled?(s.params, context)
|
32
34
|
Unleash.logger.debug "Strategy #{s.name} returned #{r} with context: #{context}" #"for params #{s.params} "
|
33
35
|
r
|
34
|
-
}.any?
|
36
|
+
}.any? || self.strategies.empty? )
|
35
37
|
result ||= default_result
|
36
38
|
|
37
39
|
Unleash.logger.debug "FeatureToggle (enabled:#{self.enabled} default_result:#{default_result} and Strategies combined returned #{result})"
|
@@ -28,8 +28,12 @@ module Unleash
|
|
28
28
|
Unleash.logger.error "stacktrace: #{e.backtrace}"
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
if self.retry_count > self.max_exceptions
|
32
|
+
Unleash.logger.info "thread #{name} retry_count (#{self.retry_count}) exceeded max_exceptions (#{self.max_exceptions}). Stopping with retries."
|
33
|
+
break
|
34
|
+
end
|
32
35
|
end
|
36
|
+
Unleash.logger.info "thread #{name} ended"
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
@@ -11,6 +11,7 @@ module Unleash
|
|
11
11
|
def is_enabled?(params = {}, context)
|
12
12
|
return false unless params.is_a?(Hash) && params.has_key?('percentage')
|
13
13
|
return false unless context.class.name == 'Unleash::Context'
|
14
|
+
return false if context.session_id.empty?
|
14
15
|
|
15
16
|
percentage = Integer(params['percentage'] || 0)
|
16
17
|
(percentage > 0 && Util.get_normalized_number(context.session_id, params['groupId'] || "") <= percentage)
|
@@ -11,6 +11,7 @@ module Unleash
|
|
11
11
|
def is_enabled?(params = {}, context)
|
12
12
|
return false unless params.is_a?(Hash) && params.has_key?('percentage')
|
13
13
|
return false unless context.class.name == 'Unleash::Context'
|
14
|
+
return false if context.user_id.empty?
|
14
15
|
|
15
16
|
percentage = Integer(params['percentage'] || 0)
|
16
17
|
(percentage > 0 && Util.get_normalized_number(context.user_id, params['groupId'] || "") <= percentage)
|
data/lib/unleash/version.rb
CHANGED
data/unleash-client.gemspec
CHANGED
@@ -11,8 +11,9 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.licenses = ["Apache-2.0"]
|
12
12
|
|
13
13
|
spec.summary = %q{Unleash feature toggle client.}
|
14
|
-
spec.description = %q{
|
15
|
-
over all feature toggles across all your applications and services.}
|
14
|
+
spec.description = %q{This is the ruby client for Unleash, a powerful feature toggle system
|
15
|
+
that gives you a great overview over all feature toggles across all your applications and services.}
|
16
|
+
|
16
17
|
spec.homepage = "https://github.com/unleash/unleash-client-ruby"
|
17
18
|
|
18
19
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
@@ -25,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
25
26
|
|
26
27
|
spec.add_dependency "murmurhash3", "~> 0.1.6"
|
27
28
|
|
28
|
-
spec.add_development_dependency "bundler", "~>
|
29
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
29
30
|
spec.add_development_dependency "rake", "~> 10.0"
|
30
31
|
spec.add_development_dependency "rspec", "~> 3.0"
|
31
32
|
spec.add_development_dependency "webmock", "~> 3.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unleash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renato Arruda
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: murmurhash3
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '2.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '2.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,8 +95,8 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
description: |-
|
98
|
-
|
99
|
-
over all feature toggles across all your applications and services.
|
98
|
+
This is the ruby client for Unleash, a powerful feature toggle system
|
99
|
+
that gives you a great overview over all feature toggles across all your applications and services.
|
100
100
|
email:
|
101
101
|
- rarruda@rarruda.org
|
102
102
|
executables: []
|