determinator 0.1.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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +34 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/determinator.gemspec +31 -0
- data/docs/img/determinator.jpg +0 -0
- data/examples/determinator-rails/.env +7 -0
- data/examples/determinator-rails/.gitignore +15 -0
- data/examples/determinator-rails/Gemfile +16 -0
- data/examples/determinator-rails/Gemfile.lock +163 -0
- data/examples/determinator-rails/Procfile +2 -0
- data/examples/determinator-rails/README.md +35 -0
- data/examples/determinator-rails/Rakefile +3 -0
- data/examples/determinator-rails/app/controllers/application_controller.rb +20 -0
- data/examples/determinator-rails/app/controllers/index_controller.rb +9 -0
- data/examples/determinator-rails/app/jobs/application_job.rb +2 -0
- data/examples/determinator-rails/bin/bundle +3 -0
- data/examples/determinator-rails/bin/rails +4 -0
- data/examples/determinator-rails/bin/rake +4 -0
- data/examples/determinator-rails/config.ru +3 -0
- data/examples/determinator-rails/config/application.rb +18 -0
- data/examples/determinator-rails/config/boot.rb +3 -0
- data/examples/determinator-rails/config/environment.rb +2 -0
- data/examples/determinator-rails/config/environments/development.rb +18 -0
- data/examples/determinator-rails/config/environments/production.rb +17 -0
- data/examples/determinator-rails/config/environments/test.rb +13 -0
- data/examples/determinator-rails/config/initializers/determinator.rb +7 -0
- data/examples/determinator-rails/config/initializers/filter_parameter_logging.rb +1 -0
- data/examples/determinator-rails/config/initializers/new_framework_defaults.rb +3 -0
- data/examples/determinator-rails/config/initializers/wrap_parameters.rb +3 -0
- data/examples/determinator-rails/config/puma.rb +5 -0
- data/examples/determinator-rails/config/routes.rb +6 -0
- data/examples/determinator-rails/config/secrets.yml +8 -0
- data/examples/determinator-rails/config/sidekiq.yml +2 -0
- data/examples/determinator-rails/public/favicon.ico +0 -0
- data/examples/determinator-rails/public/robots.txt +5 -0
- data/lib/determinator.rb +16 -0
- data/lib/determinator/actor_control.rb +41 -0
- data/lib/determinator/control.rb +119 -0
- data/lib/determinator/feature.rb +48 -0
- data/lib/determinator/retrieve/routemaster.rb +70 -0
- data/lib/determinator/retrieve/routemaster_indexing_middleware.rb +28 -0
- data/lib/determinator/target_group.rb +28 -0
- data/lib/determinator/version.rb +3 -0
- metadata +193 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'routemaster/drain/caching'
|
3
|
+
require 'routemaster/responses/hateoas_response'
|
4
|
+
require 'determinator/retrieve/routemaster_indexing_middleware'
|
5
|
+
|
6
|
+
module Determinator
|
7
|
+
module Retrieve
|
8
|
+
# A storage and retrieval engine for Determinator using routemaster-drain.
|
9
|
+
#
|
10
|
+
# To use this correctly you will need the following environment variables set to appropriate values
|
11
|
+
# for your instance of Routemaster:
|
12
|
+
#
|
13
|
+
# ROUTEMASTER_DRAIN_TOKENS
|
14
|
+
# ROUTEMASTER_DRAIN_REDIS
|
15
|
+
# ROUTEMASTER_CACHE_REDIS
|
16
|
+
# ROUTEMASTER_CACHE_AUTH
|
17
|
+
# ROUTEMASTER_QUEUE_NAME
|
18
|
+
# ROUTEMASTER_CALLBACK_URL
|
19
|
+
class Routemaster
|
20
|
+
attr_reader :routemaster_app
|
21
|
+
|
22
|
+
CALLBACK_PATH = (URI.parse(ENV['ROUTEMASTER_CALLBACK_URL']).path rescue '/events').freeze
|
23
|
+
|
24
|
+
# @param :discovery_url [String] The bootstrap URL of the instance of Florence which defines Features.
|
25
|
+
def initialize(discovery_url:)
|
26
|
+
client = ::Routemaster::APIClient.new(
|
27
|
+
response_class: ::Routemaster::Responses::HateoasResponse,
|
28
|
+
middlewares: [RoutemasterIndexingMiddleware]
|
29
|
+
)
|
30
|
+
@routemaster = client.discover(discovery_url)
|
31
|
+
@routemaster_app = ::Routemaster::Drain::Caching.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def retrieve(feature_name)
|
35
|
+
key = self.class.index_cache_key(feature_name)
|
36
|
+
feature_id = ::Routemaster::Config.cache_redis.get(key)
|
37
|
+
return unless feature_id
|
38
|
+
|
39
|
+
obj = @routemaster.feature.show(feature_id)
|
40
|
+
|
41
|
+
Feature.new(
|
42
|
+
name: obj.body.name,
|
43
|
+
identifier: obj.body.identifier,
|
44
|
+
bucket_type: obj.body.bucket_type,
|
45
|
+
target_groups: obj.body.target_groups.map { |tg|
|
46
|
+
TargetGroup.new(
|
47
|
+
rollout: tg.rollout,
|
48
|
+
constraints: tg.constraints.to_hash
|
49
|
+
)
|
50
|
+
},
|
51
|
+
variants: obj.body.variants.to_hash,
|
52
|
+
overrides: obj.body.overrides.to_hash
|
53
|
+
)
|
54
|
+
rescue ::Routemaster::Errors::ResourceNotFound
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
# Automatically configures the rails router to listen for Features with routemaster
|
59
|
+
#
|
60
|
+
# @param route_mapper [ActionDispatch::Routing::Mapper] The rails mapper, 'self' within the `routes.draw` block
|
61
|
+
def configure_rails_router(route_mapper)
|
62
|
+
route_mapper.mount routemaster_app, at: CALLBACK_PATH
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.index_cache_key(feature_name)
|
66
|
+
"determinator_index:#{feature_name}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Determinator
|
2
|
+
module Retrieve
|
3
|
+
# Middleware which indexes features by their name, so we can look up a feature by name
|
4
|
+
# and find the details (which are only accessible by ID)
|
5
|
+
class RoutemasterIndexingMiddleware
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
content = JSON.parse(env.body)
|
12
|
+
|
13
|
+
if content_describes_feature?(content)
|
14
|
+
key = Routemaster.index_cache_key(content['name'])
|
15
|
+
::Routemaster::Config.cache_redis.set(key, content['id'])
|
16
|
+
end
|
17
|
+
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def content_describes_feature?(content)
|
24
|
+
content['id'] && content['name'] && content['bucket_type']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Determinator
|
2
|
+
class TargetGroup
|
3
|
+
attr_reader :rollout, :constraints
|
4
|
+
|
5
|
+
def initialize(rollout:, constraints: {})
|
6
|
+
@rollout = rollout
|
7
|
+
@constraints = constraints
|
8
|
+
end
|
9
|
+
|
10
|
+
def rollout_percent
|
11
|
+
# Rollout is out of 65536 because the highest rollout indicator
|
12
|
+
# (which is a 16 bit integer) can be is 65,535. 100% rollout
|
13
|
+
# needs to include the highest indicator, and 0% needs to not include
|
14
|
+
# the lowest indicator.
|
15
|
+
Rational(rollout, 65_536)
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
pc = (rollout_percent * 100).to_f.round(1)
|
20
|
+
"<#{pc}% of those matching: #{constraints}>"
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other)
|
24
|
+
return false unless other.is_a?(self.class)
|
25
|
+
other.rollout == rollout && other.constraints == constraints
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: determinator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- JP Hastings-Spital
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-04-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: routemaster-drain
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.13'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.13'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-its
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.2'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard-rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4.7'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '4.7'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: factory_girl
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '4.8'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '4.8'
|
111
|
+
description:
|
112
|
+
email:
|
113
|
+
- jp@deliveroo.co.uk
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".gitignore"
|
119
|
+
- ".rspec"
|
120
|
+
- ".travis.yml"
|
121
|
+
- CODE_OF_CONDUCT.md
|
122
|
+
- Gemfile
|
123
|
+
- Guardfile
|
124
|
+
- LICENSE.txt
|
125
|
+
- README.md
|
126
|
+
- Rakefile
|
127
|
+
- bin/console
|
128
|
+
- bin/setup
|
129
|
+
- determinator.gemspec
|
130
|
+
- docs/img/determinator.jpg
|
131
|
+
- examples/determinator-rails/.env
|
132
|
+
- examples/determinator-rails/.gitignore
|
133
|
+
- examples/determinator-rails/Gemfile
|
134
|
+
- examples/determinator-rails/Gemfile.lock
|
135
|
+
- examples/determinator-rails/Procfile
|
136
|
+
- examples/determinator-rails/README.md
|
137
|
+
- examples/determinator-rails/Rakefile
|
138
|
+
- examples/determinator-rails/app/controllers/application_controller.rb
|
139
|
+
- examples/determinator-rails/app/controllers/index_controller.rb
|
140
|
+
- examples/determinator-rails/app/jobs/application_job.rb
|
141
|
+
- examples/determinator-rails/bin/bundle
|
142
|
+
- examples/determinator-rails/bin/rails
|
143
|
+
- examples/determinator-rails/bin/rake
|
144
|
+
- examples/determinator-rails/config.ru
|
145
|
+
- examples/determinator-rails/config/application.rb
|
146
|
+
- examples/determinator-rails/config/boot.rb
|
147
|
+
- examples/determinator-rails/config/environment.rb
|
148
|
+
- examples/determinator-rails/config/environments/development.rb
|
149
|
+
- examples/determinator-rails/config/environments/production.rb
|
150
|
+
- examples/determinator-rails/config/environments/test.rb
|
151
|
+
- examples/determinator-rails/config/initializers/determinator.rb
|
152
|
+
- examples/determinator-rails/config/initializers/filter_parameter_logging.rb
|
153
|
+
- examples/determinator-rails/config/initializers/new_framework_defaults.rb
|
154
|
+
- examples/determinator-rails/config/initializers/wrap_parameters.rb
|
155
|
+
- examples/determinator-rails/config/puma.rb
|
156
|
+
- examples/determinator-rails/config/routes.rb
|
157
|
+
- examples/determinator-rails/config/secrets.yml
|
158
|
+
- examples/determinator-rails/config/sidekiq.yml
|
159
|
+
- examples/determinator-rails/public/favicon.ico
|
160
|
+
- examples/determinator-rails/public/robots.txt
|
161
|
+
- lib/determinator.rb
|
162
|
+
- lib/determinator/actor_control.rb
|
163
|
+
- lib/determinator/control.rb
|
164
|
+
- lib/determinator/feature.rb
|
165
|
+
- lib/determinator/retrieve/routemaster.rb
|
166
|
+
- lib/determinator/retrieve/routemaster_indexing_middleware.rb
|
167
|
+
- lib/determinator/target_group.rb
|
168
|
+
- lib/determinator/version.rb
|
169
|
+
homepage: https://github.com/deliveroo/determinator
|
170
|
+
licenses:
|
171
|
+
- MIT
|
172
|
+
metadata: {}
|
173
|
+
post_install_message:
|
174
|
+
rdoc_options: []
|
175
|
+
require_paths:
|
176
|
+
- lib
|
177
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
requirements: []
|
188
|
+
rubyforge_project:
|
189
|
+
rubygems_version: 2.5.1
|
190
|
+
signing_key:
|
191
|
+
specification_version: 4
|
192
|
+
summary: Determine which experiments and features a specific actor should see.
|
193
|
+
test_files: []
|