flipper-cloud 0.25.4 → 0.26.0.rc1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c798fcaaf0f9c858240f652507202cb26790aca64dc428b5ea4447b54b290534
4
- data.tar.gz: eb25193626f19f4bba50e6a1be9dea0f9a5e9b62b94097fb76a027f5c9986cd8
3
+ metadata.gz: d9e4a729d720d4feabbe8a3f7f1f1c702e108e3809a63b306c89f0abfc6a8c8d
4
+ data.tar.gz: 9d86849582da02516dcdc3552e38c380161014056b30404c241597d6af929bf3
5
5
  SHA512:
6
- metadata.gz: 4aba0c24f6009023a38441e5e81c20ed20c71aeb0e0a4b2ff81dd1c30d744a0f3d811a58552da599b1ff9177cb8f3b093e85dd385f903fe6fa57e4a483a83a76
7
- data.tar.gz: f815ec3a46d4c13355d0dfcdc403e574361df07e1e753fae2c9285439356e6a2e0ff19a2b5516b1137d99d86efe423b64422b4e5aacaf37c99ecc7d4a1746449
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.4'.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.4
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-07 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.4
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.4
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