determinator 2.3.1 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08378908b45b61bc3c88232e1e480db1200acfe98d3b42dfd10e27420067b5e8'
4
- data.tar.gz: ee822d9401d3c8a0019ae45ecdebd1f2becd56e7081764dd92ecbba9a30b6fa5
3
+ metadata.gz: b505247b6902fb3768389da7b5a20e625f95e5ccaec778ae7fb52e1808286b73
4
+ data.tar.gz: 659b93e86df258535f904bd90d91768767c5c1644cd578d3efe3f45a9c2aba6f
5
5
  SHA512:
6
- metadata.gz: '0288df451ba45366adfb9ffb1f76147c0e565ee647d278f00b23877490cdbb7ebd4fd1b832e46f3812616894d576ee285f509df67e54a68a69415ce6370bfc65'
7
- data.tar.gz: 93cc9692b60bc97bfcf629995bfd38afdbf00161864bec8b5b15568a0b409470d17b52ad1673270444afd7080ff857b10605cea4c0d733b41fbb633a8bf13dd5
6
+ metadata.gz: 753968e66ac00b3f0606eed33b5d1873ad23a89cce901b69e261f38263ff14f18b975a0f03e55146e8ea78dc397b1a48878f10c3b1fc6eadd4f278a78f2a7703
7
+ data.tar.gz: 46d183bc1e87d5031b43115bb63573503725f441a44603577274fef9817cd20722471bcba1b46d018beab4828bbcbf738c4de742aff0de26578178330edd2885
@@ -10,6 +10,10 @@ jobs:
10
10
  steps:
11
11
  - checkout
12
12
 
13
+ - run:
14
+ name: Install bundler
15
+ command: gem install bundler -v 2.1.4
16
+
13
17
  - run:
14
18
  name: Bundle Install
15
19
  command: bundle install
@@ -30,6 +34,10 @@ jobs:
30
34
  steps:
31
35
  - checkout
32
36
 
37
+ - run:
38
+ name: Install bundler
39
+ command: gem install bundler -v 2.1.4
40
+
33
41
  - run:
34
42
  name: Bundle Install
35
43
  command: bundle install
@@ -50,6 +58,10 @@ jobs:
50
58
  steps:
51
59
  - checkout
52
60
 
61
+ - run:
62
+ name: Install bundler
63
+ command: gem install bundler -v 2.1.4
64
+
53
65
  - run:
54
66
  name: Bundle Install
55
67
  command: bundle install
@@ -1,3 +1,39 @@
1
+ # 2.5.0
2
+
3
+ Feature:
4
+ - Add fixed determinations
5
+
6
+ # 2.4.4
7
+
8
+ Bug fix:
9
+ - Count repeated determinations instead of tracking separately
10
+
11
+ # 2.4.3
12
+
13
+ Feature:
14
+ - Add Sinatra endpoint tracking
15
+
16
+ Bug fix:
17
+ - Remove endpoint tracking of PATH_INFO
18
+
19
+ # 2.4.2
20
+
21
+ Feature:
22
+ - Add endpoint information to tracking request
23
+
24
+ Bug fix:
25
+ - Make tracking request "start" attribute an actual time
26
+
27
+ # 2.4.1
28
+
29
+ Bug fix:
30
+ - Update "fake" retrievers to match behaviour introduced in `v2.3.1` when a feature is missing
31
+
32
+ # 2.4.0
33
+
34
+ Feature:
35
+ - Add tracker middleware
36
+
1
37
  # v2.3.1 (2019-05-25)
2
38
 
3
39
  Feature:
data/README.md CHANGED
@@ -204,7 +204,7 @@ variant = determinator.which_variant(
204
204
  app_version: "1.2.3"
205
205
  }
206
206
  )
207
- ```
207
+ ```
208
208
  The `app_version` constraint for that flag needs to follow ruby gem version constraints. We support the following operators: `>, <, >=, <=, ~>`. For example:
209
209
  `app_version: ">=1.2.0"`
210
210
 
@@ -220,6 +220,8 @@ Determinator.configure(retrieval: nil)
220
220
 
221
221
  * Tag your rspec test with `:determinator_support`, so the `forced_determination` helper method will be available.
222
222
 
223
+ Please note, `RSpec::Determinator` mocks a determination _outcome_, not the process of choosing one. Set the `only_for` argument to be the properties you require for Determinator to return the specified outcome. At the moment this mock does not allow for the testing of the `id` or `guid` arguments (only the properties).
224
+
223
225
  ```ruby
224
226
  RSpec.describe "something", :determinator_support do
225
227
 
@@ -251,6 +253,73 @@ end
251
253
 
252
254
  * Check out [the specs for `RSpec::Determinator`](spec/rspec/determinator_spec.rb) to find out what you can do!
253
255
 
256
+ ## Tracking
257
+
258
+ The library includes a middleware to track all determinations being made, allowing logging them at the end of the request
259
+ (including some useful request metrics).
260
+
261
+ To enable it, e.g. in Rails:
262
+
263
+ ```ruby
264
+ # config/application.rb
265
+
266
+ require 'determinator/tracking/rack/middleware'
267
+
268
+ # possibly near the top of your stack, in case other middlewares make determinations
269
+ config.middleware.use Determinator::Tracking::Rack::Middleware
270
+ ```
271
+
272
+ or for Sidekiq:
273
+
274
+ ```ruby
275
+ # config/initializers/sidekiq.rb
276
+
277
+ require 'determinator/tracking/sidekiq/middleware'
278
+
279
+ Sidekiq.configure_server do |config|
280
+ config.server_middleware do |chain|
281
+ chain.add Determinator::Tracking::Sidekiq::Middleware
282
+ end
283
+ end
284
+ ```
285
+
286
+ ```ruby
287
+ # config/initializers/determinator.rb
288
+
289
+ require 'determinator/tracking'
290
+
291
+ Determinator::Tracking.on_request do |r|
292
+ Rails.logger.info("tag=determinator_request endpoint=#{r.endpoint} type=#{r.type} request_time=#{r.time} error=#{r.error?} response_status=#{r.attributes[:status]} sidekiq_queue=#{r.attributes[:queue]}")
293
+ r.determinations.each do |d|
294
+ Rails.logger.info("tag=determination id=#{d.id} guid=#{d.guid} flag=#{d.feature_id} result=#{d.determination}")
295
+ end
296
+ end
297
+
298
+ # The library sets the "endpoint" with information about the request or sidekiq job. If you
299
+ # have environment variables that further identify the service, e.g. ENV['APP_NAME'],
300
+ # you can configure the tracker to prepend it to the endpoint:
301
+ Determinator::Tracking.endpoint_env_vars = ['APP_NAME']
302
+
303
+ # If using an APM, you can provide trace information on the request by providing a get_context hook: e.g.
304
+
305
+ Determinator::Tracking.get_context do
306
+ span = Datadog.tracer.active_root_span
307
+ return unless span
308
+ Determinator::Tracking::Context.new(
309
+ request_id: span.trace_id,
310
+ service: span.service,
311
+ resource: span.resource,
312
+ type: span.type,
313
+ meta: span.meta
314
+ )
315
+ end
316
+ ```
317
+
318
+ NOTE: determinations will only be recorded on the threads where Determinator::Tracking is initialised via the middleware. If offloading work away from these thread (for example, by spinning up new threads within a Rack request or a Sidekiq worker), make the determinations before, and pass them through to the new threads; or, if it's not possible, collect them manually and track them in the request's thread with
319
+ ```
320
+ Determinator::Tracking.track(id, guid, feature, determination)
321
+ ```
322
+
254
323
  ## Testing this library
255
324
 
256
325
  This library makes use of the [Determinator Standard Tests](https://github.com/deliveroo/determinator-standard-tests) to ensure that it conforms to the same specification as determinator libraries in other languages. The standard tests can be updated to the latest ones available by updating the submodule:
@@ -23,11 +23,12 @@ Gem::Specification.new do |spec|
23
23
  spec.add_runtime_dependency "faraday"
24
24
  spec.add_runtime_dependency "semantic", "~> 1.6"
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.13"
26
+ spec.add_development_dependency "bundler", "~> 2.1.4"
27
27
  spec.add_development_dependency "rake", "~> 10.0"
28
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
29
  spec.add_development_dependency "rspec-its", "~> 1.2"
30
30
  spec.add_development_dependency "guard-rspec", "~> 4.7"
31
31
  spec.add_development_dependency "factory_girl", "~> 4.8"
32
32
  spec.add_development_dependency 'webmock'
33
+ spec.add_development_dependency "sidekiq"
33
34
  end
@@ -2,10 +2,12 @@ require 'determinator/version'
2
2
  require 'determinator/control'
3
3
  require 'determinator/feature'
4
4
  require 'determinator/target_group'
5
+ require 'determinator/fixed_determination'
5
6
  require 'determinator/cache/fetch_wrapper'
6
7
  require 'determinator/serializers/json'
7
8
  require 'determinator/missing_response'
8
9
  require 'determinator/error_response'
10
+ require 'determinator/tracking'
9
11
 
10
12
 
11
13
  module Determinator
@@ -83,6 +85,7 @@ module Determinator
83
85
  end
84
86
 
85
87
  def notice_determination(id, guid, feature, determination)
88
+ Determinator::Tracking.track(id, guid, feature, determination)
86
89
  return unless @determination_callback
87
90
  @determination_callback.call(id, guid, feature, determination)
88
91
  end
@@ -81,6 +81,14 @@ module Determinator
81
81
 
82
82
  return feature.override_value_for(id) if feature.overridden_for?(id)
83
83
 
84
+ fixed_determination = choose_fixed_determination(feature, properties)
85
+ # Given constraints have specified that this actor's determination should be fixed
86
+ if fixed_determination
87
+ return false unless fixed_determination.feature_on
88
+ return true unless feature.experiment?
89
+ return fixed_determination.variant
90
+ end
91
+
84
92
  target_group = choose_target_group(feature, properties)
85
93
  # Given constraints have excluded this actor from this experiment
86
94
  return false unless target_group
@@ -106,23 +114,34 @@ module Determinator
106
114
  false
107
115
  end
108
116
 
117
+ def choose_fixed_determination(feature, properties)
118
+ # Keys and values must be strings
119
+ normalised_properties = normalise_properties(properties)
120
+
121
+ feature.fixed_determinations.find { |fd|
122
+ matches_constraints(normalised_properties, fd.constraints)
123
+ }
124
+ end
125
+
109
126
  def choose_target_group(feature, properties)
110
127
  # Keys and values must be strings
111
- normalised_properties = properties.each_with_object({}) do |(name, values), hash|
112
- hash[name.to_s] = [*values].map(&:to_s)
113
- end
128
+ normalised_properties = normalise_properties(properties)
114
129
 
115
130
  feature.target_groups.select { |tg|
116
131
  next false unless tg.rollout.between?(1, 65_536)
117
132
 
118
- tg.constraints.reduce(true) do |fit, (scope, *required)|
119
- present = [*normalised_properties[scope]]
120
- fit && matches_requirements?(scope, required, present)
121
- end
133
+ matches_constraints(normalised_properties, tg.constraints)
122
134
  # Must choose target group deterministically, if more than one match
123
135
  }.sort_by { |tg| tg.rollout }.last
124
136
  end
125
137
 
138
+ def matches_constraints(normalised_properties, constraints)
139
+ constraints.reduce(true) do |fit, (scope, *required)|
140
+ present = [*normalised_properties[scope]]
141
+ fit && matches_requirements?(scope, required, present)
142
+ end
143
+ end
144
+
126
145
  def matches_requirements?(scope, required, present)
127
146
  case scope
128
147
  when "app_version" then has_any_app_version?(required, present)
@@ -205,5 +224,13 @@ module Determinator
205
224
 
206
225
  raise ArgumentError, "A variant should have been found by this point, there is a bug in the code."
207
226
  end
227
+
228
+ private
229
+
230
+ def normalise_properties(properties)
231
+ properties.each_with_object({}) do |(name, values), hash|
232
+ hash[name.to_s] = [*values].map(&:to_s)
233
+ end
234
+ end
208
235
  end
209
236
  end
@@ -3,13 +3,14 @@ module Determinator
3
3
  #
4
4
  # @attr_reader [nil,Hash<String,Integer>] variants The variants for this experiment, with the name of the variant as the key and the weight as the value. Will be nil for non-experiments.
5
5
  class Feature
6
- attr_reader :name, :identifier, :bucket_type, :variants, :target_groups, :active, :winning_variant
6
+ attr_reader :name, :identifier, :bucket_type, :variants, :target_groups, :fixed_determinations, :active, :winning_variant
7
7
 
8
- def initialize(name:, identifier:, bucket_type:, target_groups:, variants: {}, overrides: {}, active: false, winning_variant: nil)
8
+ def initialize(name:, identifier:, bucket_type:, target_groups:, fixed_determinations: [], variants: {}, overrides: {}, active: false, winning_variant: nil)
9
9
  @name = name.to_s
10
- @identifier = (identifier || name).to_s
10
+ @identifier = identifier.to_s
11
11
  @variants = variants
12
12
  @target_groups = parse_target_groups(target_groups)
13
+ @fixed_determinations = parse_fixed_determinations(fixed_determinations)
13
14
  @winning_variant = parse_outcome(winning_variant, allow_exclusion: false)
14
15
  @active = active
15
16
  @bucket_type = bucket_type.to_sym
@@ -72,14 +73,43 @@ module Determinator
72
73
 
73
74
  TargetGroup.new(
74
75
  rollout: target_group['rollout'].to_i,
75
- constraints: constraints.each_with_object({}) do |(key, value), hash|
76
- hash[key.to_s] = [*value].map(&:to_s)
77
- end
76
+ constraints: parse_constraints(constraints)
78
77
  )
79
78
 
80
79
  # Invalid target groups are ignored
81
80
  rescue
82
81
  nil
83
82
  end
83
+
84
+ def parse_fixed_determinations(fixed_determinations)
85
+ fixed_determinations.map(&method(:parse_fixed_determination)).compact
86
+ end
87
+
88
+ def parse_fixed_determination(fixed_determination)
89
+ return fixed_determination if fixed_determination.is_a? FixedDetermination
90
+
91
+ variant = fixed_determination['variant']
92
+ return nil if variant && !variants.keys.include?(variant)
93
+
94
+ # if a variant is present the fixed determination should always be on
95
+ return nil if variant && !fixed_determination['feature_on']
96
+
97
+ constraints = fixed_determination['constraints'].to_h
98
+
99
+ FixedDetermination.new(
100
+ feature_on: fixed_determination['feature_on'],
101
+ variant: variant,
102
+ constraints: parse_constraints(constraints)
103
+ )
104
+ # Invalid fixed determinations are ignored
105
+ rescue
106
+ nil
107
+ end
108
+
109
+ def parse_constraints(constraints)
110
+ constraints.each_with_object({}) do |(key, value), hash|
111
+ hash[key.to_s] = [*value].map(&:to_s)
112
+ end
113
+ end
84
114
  end
85
115
  end
@@ -0,0 +1,20 @@
1
+ module Determinator
2
+ class FixedDetermination
3
+ attr_reader :feature_on, :variant, :constraints
4
+
5
+ def initialize(feature_on:, variant:, constraints: {})
6
+ @feature_on = feature_on
7
+ @variant = variant
8
+ @constraints = constraints
9
+ end
10
+
11
+ def inspect
12
+ "<feature_on: #{feature_on}, variant: #{variant}, constraints: #{constraints}"
13
+ end
14
+
15
+ def ==(other)
16
+ return false unless other.is_a?(self.class)
17
+ other.feature_on == feature_on && other.variant == variant && other.constraints == constraints
18
+ end
19
+ end
20
+ end
@@ -10,7 +10,7 @@ module Determinator
10
10
 
11
11
  # @param name [string,symbol] The name of the feature to retrieve
12
12
  def retrieve(name)
13
- @features[name.to_s]
13
+ @features.fetch(name.to_s, MissingResponse.new)
14
14
  end
15
15
 
16
16
  # @param feature [Determinator::Feature] The feature to store
@@ -10,6 +10,7 @@ module Determinator
10
10
  # The Control class will assume a nil return from this method
11
11
  # means the feature doesn't exist, so in turn will return `false`.
12
12
  def retrieve(_)
13
+ MissingResponse.new
13
14
  end
14
15
  end
15
16
  end
@@ -12,14 +12,15 @@ module Determinator
12
12
  obj = string_or_hash.is_a?(Hash) ? string_or_hash : ::JSON.parse(string_or_hash)
13
13
 
14
14
  Determinator::Feature.new(
15
- name: obj['name'],
16
- identifier: obj['identifier'],
17
- bucket_type: obj['bucket_type'],
18
- active: (obj['active'] === true),
19
- target_groups: obj['target_groups'],
20
- variants: obj['variants'].to_h,
21
- overrides: obj['overrides'].to_h,
22
- winning_variant: obj['winning_variant'].to_s,
15
+ name: obj['name'],
16
+ identifier: obj['identifier'],
17
+ bucket_type: obj['bucket_type'],
18
+ active: (obj['active'] === true),
19
+ target_groups: obj['target_groups'],
20
+ fixed_determinations: obj['fixed_determinations'].to_a,
21
+ variants: obj['variants'].to_h,
22
+ overrides: obj['overrides'].to_h,
23
+ winning_variant: obj['winning_variant'].to_s,
23
24
  )
24
25
  end
25
26
  end
@@ -0,0 +1,74 @@
1
+ require 'determinator/tracking/tracker'
2
+ require 'determinator/tracking/context'
3
+
4
+ module Determinator
5
+ module Tracking
6
+ class << self
7
+ attr_reader :endpoint_env_vars
8
+
9
+ def instance
10
+ Thread.current[:determinator_tracker]
11
+ end
12
+
13
+ def start!(type)
14
+ Thread.current[:determinator_tracker] = Tracker.new(type)
15
+ end
16
+
17
+ def finish!(endpoint:, error:, **attributes)
18
+ return false unless started?
19
+ request = instance.finish!(endpoint: endpoint, error: error, **attributes)
20
+ clear!
21
+ report(request)
22
+ request
23
+ end
24
+
25
+ def clear!
26
+ Thread.current[:determinator_tracker] = nil
27
+ end
28
+
29
+ def started?
30
+ !!instance
31
+ end
32
+
33
+ def track(id, guid, feature, determination)
34
+ return false unless started?
35
+ instance.track(id, guid, feature, determination)
36
+ end
37
+
38
+ def on_request(&block)
39
+ @on_request = block
40
+ end
41
+
42
+ def report(request)
43
+ return unless @on_request
44
+ @on_request.call(request)
45
+ end
46
+
47
+ def get_context(&block)
48
+ @get_context = block
49
+ end
50
+
51
+ def context
52
+ return unless @get_context
53
+ @get_context.call
54
+ rescue
55
+ nil
56
+ end
57
+
58
+ def clear_hooks!
59
+ @on_request = nil
60
+ @get_context = nil
61
+ end
62
+
63
+ def endpoint_env_vars=(vars)
64
+ @endpoint_env_vars = Array(vars)
65
+ end
66
+
67
+ def collect_endpoint_info(parts)
68
+ endpoint = Array(Determinator::Tracking.endpoint_env_vars).map{ |v| ENV[v] }
69
+ endpoint += Array(parts)
70
+ endpoint.reject{ |p| p.nil? || p == ''}.join(' ')
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,15 @@
1
+ module Determinator
2
+ module Tracking
3
+ class Context
4
+ attr_reader :request_id, :service, :resource
5
+
6
+ def initialize(request_id: nil, service: nil, resource: nil, type: nil, meta: {})
7
+ @request_id = request_id
8
+ @service = service
9
+ @resource = resource
10
+ @type = type
11
+ @meta = meta
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ module Determinator
2
+ module Tracking
3
+ class Determination
4
+ attr_reader :id, :guid, :feature_id, :determination
5
+
6
+ def initialize(id:, guid:, feature_id:, determination:)
7
+ @id = id
8
+ @guid = guid
9
+ @feature_id = feature_id
10
+ @determination = determination
11
+ end
12
+
13
+ def ==(other)
14
+ id == other.id && guid == other.guid && feature_id == other.feature_id && determination == other.determination
15
+ end
16
+
17
+ alias eql? ==
18
+
19
+ def hash
20
+ [id, guid, feature_id, determination].hash
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,43 @@
1
+ require 'determinator/tracking'
2
+
3
+ module Determinator
4
+ module Tracking
5
+ module Rack
6
+ class Middleware
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ Determinator::Tracking.start!(:rack)
13
+ status, headers, response = @app.call(env)
14
+ [status, headers, response]
15
+ rescue
16
+ error = true
17
+ raise
18
+ ensure
19
+ Determinator::Tracking.finish!(
20
+ status: status,
21
+ error: !!error,
22
+ endpoint: extract_endpoint(env)
23
+ )
24
+ end
25
+
26
+ private
27
+
28
+ def extract_endpoint(env)
29
+ parts = if params = env['action_dispatch.request.path_parameters']
30
+ [env['REQUEST_METHOD'], [params[:controller], params[:action]].join('#')]
31
+ elsif env['sinatra.route']
32
+ [env['sinatra.route']]
33
+ else
34
+ [env['REQUEST_METHOD']]
35
+ end
36
+ Determinator::Tracking.collect_endpoint_info(parts)
37
+ rescue
38
+ env['PATH_INFO']
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,22 @@
1
+ module Determinator
2
+ module Tracking
3
+ class Request
4
+ attr_reader :start, :type, :endpoint, :time, :error, :attributes, :determinations, :context
5
+
6
+ def initialize(start:, type:, endpoint:, time:, error:, attributes:, determinations:, context: nil)
7
+ @start = start
8
+ @type = type
9
+ @time = time
10
+ @error = error
11
+ @attributes = attributes
12
+ @determinations = determinations
13
+ @endpoint = endpoint
14
+ @context = context
15
+ end
16
+
17
+ def error?
18
+ error
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ require 'determinator/tracking'
2
+
3
+ module Determinator
4
+ module Tracking
5
+ module Sidekiq
6
+ class Middleware
7
+ # @param [Object] worker the worker instance
8
+ # @param [Hash] job the full job payload
9
+ # * @see https://github.com/mperham/sidekiq/wiki/Job-Format
10
+ # @param [String] queue the name of the queue the job was pulled from
11
+ # @yield the next middleware in the chain or worker `perform` method
12
+ # @return [Void]
13
+ def call(worker, job, queue)
14
+ begin
15
+ Determinator::Tracking.start!(:sidekiq)
16
+ yield
17
+ rescue => ex
18
+ error = true
19
+ raise
20
+ ensure
21
+ Determinator::Tracking.finish!(
22
+ endpoint: Determinator::Tracking.collect_endpoint_info(worker.class.name),
23
+ queue: queue,
24
+ error: !!error
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,48 @@
1
+ require 'determinator/tracking/determination'
2
+ require 'determinator/tracking/request'
3
+
4
+ module Determinator
5
+ module Tracking
6
+ class Tracker
7
+ attr_reader :type, :determinations
8
+
9
+ def initialize(type)
10
+ @determinations = Hash.new(0)
11
+ @type = type
12
+ @monotonic_start = now
13
+ @start = Time.now
14
+ end
15
+
16
+ def track(id, guid, feature, determination)
17
+ determinations[
18
+ Determinator::Tracking::Determination.new(
19
+ id: id,
20
+ guid: guid,
21
+ feature_id: feature.identifier,
22
+ determination: determination
23
+ )
24
+ ] += 1
25
+ end
26
+
27
+ def finish!(endpoint:, error:, **attributes)
28
+ request_time = now - @monotonic_start
29
+ Determinator::Tracking::Request.new(
30
+ start: @start,
31
+ type: type,
32
+ time: request_time,
33
+ endpoint: endpoint,
34
+ error: error,
35
+ attributes: attributes,
36
+ determinations: determinations,
37
+ context: Determinator::Tracking.context
38
+ )
39
+ end
40
+
41
+ private
42
+
43
+ def now
44
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,3 @@
1
1
  module Determinator
2
- VERSION = '2.3.1'
2
+ VERSION = '2.5.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: determinator
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.1
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Hastings-Spital
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-25 00:00:00.000000000 Z
11
+ date: 2020-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.13'
47
+ version: 2.1.4
48
48
  type: :development
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: '1.13'
54
+ version: 2.1.4
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -136,7 +136,21 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
- description:
139
+ - !ruby/object:Gem::Dependency
140
+ name: sidekiq
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description:
140
154
  email:
141
155
  - jp@deliveroo.co.uk
142
156
  executables: []
@@ -196,6 +210,7 @@ files:
196
210
  - lib/determinator/control.rb
197
211
  - lib/determinator/error_response.rb
198
212
  - lib/determinator/feature.rb
213
+ - lib/determinator/fixed_determination.rb
199
214
  - lib/determinator/missing_response.rb
200
215
  - lib/determinator/retrieve/dynaconf.rb
201
216
  - lib/determinator/retrieve/file.rb
@@ -204,13 +219,20 @@ files:
204
219
  - lib/determinator/retrieve/null_retriever.rb
205
220
  - lib/determinator/serializers/json.rb
206
221
  - lib/determinator/target_group.rb
222
+ - lib/determinator/tracking.rb
223
+ - lib/determinator/tracking/context.rb
224
+ - lib/determinator/tracking/determination.rb
225
+ - lib/determinator/tracking/rack/middleware.rb
226
+ - lib/determinator/tracking/request.rb
227
+ - lib/determinator/tracking/sidekiq/middleware.rb
228
+ - lib/determinator/tracking/tracker.rb
207
229
  - lib/determinator/version.rb
208
230
  - lib/rspec/determinator.rb
209
231
  homepage: https://github.com/deliveroo/determinator
210
232
  licenses:
211
233
  - MIT
212
234
  metadata: {}
213
- post_install_message:
235
+ post_install_message:
214
236
  rdoc_options: []
215
237
  require_paths:
216
238
  - lib
@@ -225,9 +247,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
247
  - !ruby/object:Gem::Version
226
248
  version: '0'
227
249
  requirements: []
228
- rubyforge_project:
229
- rubygems_version: 2.7.9
230
- signing_key:
250
+ rubygems_version: 3.0.6
251
+ signing_key:
231
252
  specification_version: 4
232
253
  summary: Determine which experiments and features a specific actor should see.
233
254
  test_files: []