flipper-cloud 0.25.3 → 0.26.0.rc1

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: 07a103af16fcba0b24288ba3a8ec01c98957390ebbb971b80783e95fb06c275c
4
- data.tar.gz: de559bb7ff66d8e554d115ae53b369e6c52f86c0cde3545f8c4c759329b3b6c6
3
+ metadata.gz: d9e4a729d720d4feabbe8a3f7f1f1c702e108e3809a63b306c89f0abfc6a8c8d
4
+ data.tar.gz: 9d86849582da02516dcdc3552e38c380161014056b30404c241597d6af929bf3
5
5
  SHA512:
6
- metadata.gz: e0b3894d0ab8dcbfe2d56f2d51d7e7fa79e5be3f487236d92aebfdeed0cff378b0c455ff25f6e3f8e044cfc68d59695f4548cc111372f100bfb1709b0a6d4043
7
- data.tar.gz: 525a3ddaee6c994dd48e41d4a94ab54396ebab012ef6a13d1196b115796637aaa3e7c5a068a1ea1fdef9100eeececda2213afe6697a4d59da574b848456f7278
6
+ metadata.gz: 66fc9ed14732f2c4d64aebfdc0e835ad064349f40f595bd13604f6f1b8f8843cc587cb3e9ab83b615f4e6667869c595516e6f737722781df41c09ad51135ea06
7
+ data.tar.gz: 143fae6cb5e465e27971e59ced3c5e8059ac2bec561ddab55d4cd6d9efdacc4f158bf6a5cebc52aba131c75ca56264e856fdf502924e3a78624caf905c20b2f6
@@ -0,0 +1,31 @@
1
+ # Usage (from the repo root):
2
+ # env FLIPPER_CLOUD_TOKEN=<token> bundle exec ruby examples/cloud/threaded.rb
3
+
4
+ require_relative "./cloud_setup"
5
+ require 'bundler/setup'
6
+ require 'flipper/cloud'
7
+
8
+ pids = 5.times.map do |n|
9
+ fork {
10
+ # Check every second to see if the feature is enabled
11
+ threads = []
12
+ 5.times do
13
+ threads << Thread.new do
14
+ loop do
15
+ sleep rand
16
+
17
+ if Flipper[:stats].enabled?
18
+ puts "#{Process.pid} #{Time.now.to_i} Enabled!"
19
+ else
20
+ puts "#{Process.pid} #{Time.now.to_i} Disabled!"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ threads.map(&:join)
26
+ }
27
+ end
28
+
29
+ pids.each do |pid|
30
+ Process.waitpid pid, 0
31
+ end
@@ -0,0 +1,24 @@
1
+ # Usage (from the repo root):
2
+ # env FLIPPER_CLOUD_TOKEN=<token> bundle exec ruby examples/cloud/threaded.rb
3
+
4
+ require_relative "./cloud_setup"
5
+ require 'bundler/setup'
6
+ require 'flipper/cloud'
7
+
8
+ # Check every second to see if the feature is enabled
9
+ threads = []
10
+ 10.times do
11
+ threads << Thread.new do
12
+ loop do
13
+ sleep rand
14
+
15
+ if Flipper[:stats].enabled?
16
+ puts "#{Time.now.to_i} Enabled!"
17
+ else
18
+ puts "#{Time.now.to_i} Disabled!"
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ threads.map(&:join)
@@ -1,10 +1,11 @@
1
1
  require "socket"
2
2
  require "flipper/adapters/http"
3
+ require "flipper/adapters/poll"
4
+ require "flipper/adapters/poll/poller"
3
5
  require "flipper/adapters/memory"
4
6
  require "flipper/adapters/dual_write"
5
- require "flipper/adapters/sync"
7
+ require "flipper/adapters/sync/synchronizer"
6
8
  require "flipper/cloud/instrumenter"
7
- require "flipper/cloud/registry"
8
9
  require "brow"
9
10
 
10
11
  module Flipper
@@ -18,6 +19,12 @@ module Flipper
18
19
 
19
20
  DEFAULT_URL = "https://www.flippercloud.io/adapter".freeze
20
21
 
22
+ # Private: Keeps track of brow instances so they can be shared across
23
+ # threads.
24
+ def self.brow_instances
25
+ @brow_instances ||= Concurrent::Map.new
26
+ end
27
+
21
28
  # Public: The token corresponding to an environment on flippercloud.io.
22
29
  attr_accessor :token
23
30
 
@@ -124,13 +131,12 @@ module Flipper
124
131
  end
125
132
 
126
133
  def brow
127
- uri = URI.parse(url)
128
- uri.path = "#{uri.path}/events".squeeze("/")
129
- events_url = uri.to_s
134
+ self.class.brow_instances.compute_if_absent(url + token) do
135
+ uri = URI.parse(url)
136
+ uri.path = "#{uri.path}/events".squeeze("/")
130
137
 
131
- Registry.default.fetch(events_url) {
132
138
  Brow::Client.new({
133
- url: events_url,
139
+ url: uri.to_s,
134
140
  headers: {
135
141
  "Accept" => "application/json",
136
142
  "Content-Type" => "application/json",
@@ -138,7 +144,7 @@ module Flipper
138
144
  "Flipper-Cloud-Token" => @token,
139
145
  }
140
146
  })
141
- }
147
+ end
142
148
  end
143
149
 
144
150
  # Public: The method that will be used to synchronize local adapter with
@@ -150,18 +156,19 @@ module Flipper
150
156
  private
151
157
 
152
158
  def app_adapter
153
- sync_method == :webhook ? dual_write_adapter : sync_adapter
159
+ sync_method == :webhook ? dual_write_adapter : poll_adapter
154
160
  end
155
161
 
156
162
  def dual_write_adapter
157
163
  Flipper::Adapters::DualWrite.new(local_adapter, http_adapter)
158
164
  end
159
165
 
160
- def sync_adapter
161
- Flipper::Adapters::Sync.new(local_adapter, http_adapter, {
162
- instrumenter: instrumenter,
163
- interval: sync_interval,
164
- })
166
+ def poller
167
+ Flipper::Adapters::Poll::Poller.get(@url + @token, interval: sync_interval, remote_adapter: http_adapter).tap(&:start)
168
+ end
169
+
170
+ def poll_adapter
171
+ Flipper::Adapters::Poll.new(poller, dual_write_adapter)
165
172
  end
166
173
 
167
174
  def http_adapter
@@ -169,6 +176,8 @@ module Flipper
169
176
  url: @url,
170
177
  read_timeout: @read_timeout,
171
178
  open_timeout: @open_timeout,
179
+ write_timeout: @write_timeout,
180
+ max_retries: 0, # we'll handle retries ourselves
172
181
  debug_output: @debug_output,
173
182
  headers: {
174
183
  "Flipper-Cloud-Token" => @token,
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = '0.25.3'.freeze
2
+ VERSION = '0.26.0.rc1'.freeze
3
3
  end
@@ -72,7 +72,8 @@ RSpec.describe Flipper::Cloud::Configuration do
72
72
  stub_request(:get, /flippercloud\.io/).to_return(status: 200, body: "{}")
73
73
 
74
74
  instance = described_class.new(required_options.merge(sync_interval: 1))
75
- expect(instance.adapter.synchronizer.interval).to be(1)
75
+ poller = instance.send(:poller)
76
+ expect(poller.interval).to eq(1)
76
77
  end
77
78
 
78
79
  it "can set debug_output" do
@@ -85,7 +86,7 @@ RSpec.describe Flipper::Cloud::Configuration do
85
86
  stub_request(:get, /flippercloud\.io/).to_return(status: 200, body: "{}")
86
87
 
87
88
  instance = described_class.new(required_options)
88
- expect(instance.adapter).to be_instance_of(Flipper::Adapters::Sync)
89
+ expect(instance.adapter).to be_instance_of(Flipper::Adapters::Poll)
89
90
  end
90
91
 
91
92
  it "can override adapter block" do
@@ -234,7 +235,7 @@ RSpec.describe Flipper::Cloud::Configuration do
234
235
  expect(stub).to have_been_requested
235
236
 
236
237
  # Check that local adapter really did sync.
237
- local_adapter = instance.adapter.instance_variable_get("@local")
238
+ local_adapter = instance.local_adapter
238
239
  all = local_adapter.get_all
239
240
  expect(all.keys).to eq(["search", "history"])
240
241
  expect(all["search"][:boolean]).to eq("true")
@@ -12,10 +12,6 @@ RSpec.describe Flipper::Cloud do
12
12
 
13
13
  before do
14
14
  @instance = described_class.new(token: token)
15
- memoized_adapter = @instance.adapter
16
- sync_adapter = memoized_adapter.adapter
17
- @http_adapter = sync_adapter.instance_variable_get('@remote')
18
- @http_client = @http_adapter.instance_variable_get('@client')
19
15
  end
20
16
 
21
17
  it 'returns Flipper::DSL instance' do
@@ -26,40 +22,29 @@ RSpec.describe Flipper::Cloud do
26
22
  expect(@instance.cloud_configuration).to be_instance_of(Flipper::Cloud::Configuration)
27
23
  end
28
24
 
29
- it 'configures instance to use http adapter' do
30
- expect(@http_adapter).to be_instance_of(Flipper::Adapters::Http)
31
- end
32
-
33
- it 'sets up correct url' do
34
- uri = @http_client.instance_variable_get('@uri')
35
- expect(uri.scheme).to eq('https')
36
- expect(uri.host).to eq('www.flippercloud.io')
37
- expect(uri.path).to eq('/adapter')
38
- end
39
-
40
- it 'sets correct token header' do
41
- headers = @http_client.instance_variable_get('@headers')
42
- expect(headers['Flipper-Cloud-Token']).to eq(token)
43
- end
44
-
45
- it 'uses noop instrumenter' do
25
+ it 'configures the correct adapter' do
26
+ # pardon the nesting...
27
+ memoized_adapter = @instance.adapter
28
+ poll_adapter = memoized_adapter.adapter
29
+ dual_write_adapter = poll_adapter.adapter
30
+
31
+ expect(poll_adapter).to be_instance_of(Flipper::Adapters::Poll)
32
+ expect(dual_write_adapter).to be_instance_of(Flipper::Adapters::DualWrite)
33
+
34
+ http_adapter = dual_write_adapter.remote
35
+ client = http_adapter.client
36
+ expect(client.uri.scheme).to eq('https')
37
+ expect(client.uri.host).to eq('www.flippercloud.io')
38
+ expect(client.uri.path).to eq('/adapter')
39
+ expect(client.headers['Flipper-Cloud-Token']).to eq(token)
46
40
  expect(@instance.instrumenter).to be(Flipper::Instrumenters::Noop)
47
41
  end
48
42
  end
49
43
 
50
44
  context 'initialize with token and options' do
51
- before do
52
- stub_request(:get, /fakeflipper\.com/).to_return(status: 200, body: "{}")
53
-
54
- @instance = described_class.new(token: 'asdf', url: 'https://www.fakeflipper.com/sadpanda')
55
- memoized_adapter = @instance.adapter
56
- sync_adapter = memoized_adapter.adapter
57
- @http_adapter = sync_adapter.instance_variable_get('@remote')
58
- @http_client = @http_adapter.instance_variable_get('@client')
59
- end
60
-
61
45
  it 'sets correct url' do
62
- uri = @http_client.instance_variable_get('@uri')
46
+ @instance = described_class.new(token: 'asdf', url: 'https://www.fakeflipper.com/sadpanda')
47
+ uri = @instance.adapter.adapter.adapter.remote.client.uri
63
48
  expect(uri.scheme).to eq('https')
64
49
  expect(uri.host).to eq('www.fakeflipper.com')
65
50
  expect(uri.path).to eq('/sadpanda')
@@ -89,26 +74,26 @@ RSpec.describe Flipper::Cloud do
89
74
 
90
75
  it 'can set debug_output' do
91
76
  expect(Flipper::Adapters::Http::Client).to receive(:new)
92
- .with(hash_including(debug_output: STDOUT))
77
+ .with(hash_including(debug_output: STDOUT)).at_least(:once)
93
78
  described_class.new(token: 'asdf', debug_output: STDOUT)
94
79
  end
95
80
 
96
81
  it 'can set read_timeout' do
97
82
  expect(Flipper::Adapters::Http::Client).to receive(:new)
98
- .with(hash_including(read_timeout: 1))
83
+ .with(hash_including(read_timeout: 1)).at_least(:once)
99
84
  described_class.new(token: 'asdf', read_timeout: 1)
100
85
  end
101
86
 
102
87
  it 'can set open_timeout' do
103
88
  expect(Flipper::Adapters::Http::Client).to receive(:new)
104
- .with(hash_including(open_timeout: 1))
89
+ .with(hash_including(open_timeout: 1)).at_least(:once)
105
90
  described_class.new(token: 'asdf', open_timeout: 1)
106
91
  end
107
92
 
108
93
  if RUBY_VERSION >= '2.6.0'
109
94
  it 'can set write_timeout' do
110
95
  expect(Flipper::Adapters::Http::Client).to receive(:new)
111
- .with(hash_including(open_timeout: 1))
96
+ .with(hash_including(open_timeout: 1)).at_least(:once)
112
97
  described_class.new(token: 'asdf', open_timeout: 1)
113
98
  end
114
99
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flipper-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.25.3
4
+ version: 0.26.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-03 00:00:00.000000000 Z
11
+ date: 2022-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: flipper
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.25.3
19
+ version: 0.26.0.rc1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.25.3
26
+ version: 0.26.0.rc1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: brow
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -49,7 +49,9 @@ files:
49
49
  - examples/cloud/app.ru
50
50
  - examples/cloud/basic.rb
51
51
  - examples/cloud/cloud_setup.rb
52
+ - examples/cloud/forked.rb
52
53
  - examples/cloud/import.rb
54
+ - examples/cloud/threaded.rb
53
55
  - flipper-cloud.gemspec
54
56
  - lib/flipper-cloud.rb
55
57
  - lib/flipper/cloud.rb
@@ -59,7 +61,6 @@ files:
59
61
  - lib/flipper/cloud/instrumenter.rb
60
62
  - lib/flipper/cloud/message_verifier.rb
61
63
  - lib/flipper/cloud/middleware.rb
62
- - lib/flipper/cloud/registry.rb
63
64
  - lib/flipper/cloud/routes.rb
64
65
  - lib/flipper/version.rb
65
66
  - spec/flipper/cloud/configuration_spec.rb
@@ -84,9 +85,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
84
85
  version: '0'
85
86
  required_rubygems_version: !ruby/object:Gem::Requirement
86
87
  requirements:
87
- - - ">="
88
+ - - ">"
88
89
  - !ruby/object:Gem::Version
89
- version: '0'
90
+ version: 1.3.1
90
91
  requirements: []
91
92
  rubygems_version: 3.3.7
92
93
  signing_key:
@@ -1,46 +0,0 @@
1
- require "thread"
2
-
3
- module Flipper
4
- module Cloud
5
- class Registry
6
- def self.default
7
- @default ||= new
8
- end
9
-
10
- def initialize
11
- @mutex = Mutex.new
12
- @data = {}
13
- end
14
-
15
- def fetch(key, &block)
16
- @mutex.synchronize do
17
- if data = @data[key]
18
- data
19
- else
20
- @data[key] = yield
21
- end
22
- end
23
- end
24
-
25
- def keys
26
- @mutex.synchronize do
27
- @data.keys
28
- end
29
- end
30
-
31
- def each(&block)
32
- data = @mutex.synchronize do
33
- @data.dup
34
- end
35
-
36
- data.each(&block)
37
- end
38
-
39
- def clear
40
- @mutex.synchronize do
41
- @data = {}
42
- end
43
- end
44
- end
45
- end
46
- end