flipper 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 +4 -4
- data/Changelog.md +8 -0
- data/flipper.gemspec +2 -0
- data/lib/flipper/adapters/dual_write.rb +1 -1
- data/lib/flipper/adapters/http/client.rb +7 -11
- data/lib/flipper/adapters/http.rb +3 -1
- data/lib/flipper/adapters/poll/poller.rb +123 -0
- data/lib/flipper/adapters/poll.rb +35 -0
- data/lib/flipper/version.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +21 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b6c4a5c4ef29f126e9a08cc7fc7c70be9831b179dfc55486b88b8c5da5fdf44
|
4
|
+
data.tar.gz: aab15578901fcab2b3717813aa37d3cc057554eea3d442f264f85707d94310f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79989c8d6149b13b6c960878d4ac701f98f5e3da9b44a567092a4ace82350ec8ccffcd7e9c9ea2619a2a2508b6a392e99c05b14ab14b59b5a0b3a58b4f211150
|
7
|
+
data.tar.gz: 5192a0b9e1bebc39a28503861ba4eb35a05010a1841595e1282437c7d0694e3eccd02f215fbc6928b228948c6a02c8e9d26f85a5e23ae271fd0b32bc84bf6b53
|
data/Changelog.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
## 0.26.0.rc1
|
6
|
+
|
7
|
+
* Cloud Background Polling (https://github.com/jnunemaker/flipper/pull/682)
|
8
|
+
|
1
9
|
## 0.25.4
|
2
10
|
|
3
11
|
* Added read_only UI config option (https://github.com/jnunemaker/flipper/pull/679)
|
data/flipper.gemspec
CHANGED
@@ -14,6 +14,10 @@ module Flipper
|
|
14
14
|
|
15
15
|
HTTPS_SCHEME = "https".freeze
|
16
16
|
|
17
|
+
attr_reader :uri, :headers
|
18
|
+
attr_reader :basic_auth_username, :basic_auth_password
|
19
|
+
attr_reader :read_timeout, :open_timeout, :write_timeout, :max_retries, :debug_output
|
20
|
+
|
17
21
|
def initialize(options = {})
|
18
22
|
@uri = URI(options.fetch(:url))
|
19
23
|
@headers = DEFAULT_HEADERS.merge(options[:headers] || {})
|
@@ -22,6 +26,7 @@ module Flipper
|
|
22
26
|
@read_timeout = options[:read_timeout]
|
23
27
|
@open_timeout = options[:open_timeout]
|
24
28
|
@write_timeout = options[:write_timeout]
|
29
|
+
@max_retries = options.key?(:max_retries) ? options[:max_retries] : 0
|
25
30
|
@debug_output = options[:debug_output]
|
26
31
|
end
|
27
32
|
|
@@ -58,7 +63,8 @@ module Flipper
|
|
58
63
|
http = Net::HTTP.new(uri.host, uri.port)
|
59
64
|
http.read_timeout = @read_timeout if @read_timeout
|
60
65
|
http.open_timeout = @open_timeout if @open_timeout
|
61
|
-
|
66
|
+
http.max_retries = @max_retries if @max_retries
|
67
|
+
http.write_timeout = @write_timeout if @write_timeout
|
62
68
|
http.set_debug_output(@debug_output) if @debug_output
|
63
69
|
|
64
70
|
if uri.scheme == HTTPS_SCHEME
|
@@ -91,16 +97,6 @@ module Flipper
|
|
91
97
|
|
92
98
|
request
|
93
99
|
end
|
94
|
-
|
95
|
-
def apply_write_timeout(http)
|
96
|
-
if @write_timeout
|
97
|
-
if RUBY_VERSION >= '2.6.0'
|
98
|
-
http.write_timeout = @write_timeout
|
99
|
-
else
|
100
|
-
Kernel.warn("Warning: option :write_timeout requires Ruby version 2.6.0 or later")
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
100
|
end
|
105
101
|
end
|
106
102
|
end
|
@@ -10,7 +10,7 @@ module Flipper
|
|
10
10
|
class Http
|
11
11
|
include Flipper::Adapter
|
12
12
|
|
13
|
-
attr_reader :name
|
13
|
+
attr_reader :name, :client
|
14
14
|
|
15
15
|
def initialize(options = {})
|
16
16
|
@client = Client.new(url: options.fetch(:url),
|
@@ -19,6 +19,8 @@ module Flipper
|
|
19
19
|
basic_auth_password: options[:basic_auth_password],
|
20
20
|
read_timeout: options[:read_timeout],
|
21
21
|
open_timeout: options[:open_timeout],
|
22
|
+
write_timeout: options[:write_timeout],
|
23
|
+
max_retries: options[:max_retries],
|
22
24
|
debug_output: options[:debug_output])
|
23
25
|
@name = :http
|
24
26
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'concurrent/atomic/read_write_lock'
|
3
|
+
require 'concurrent/utility/monotonic_time'
|
4
|
+
require 'concurrent/map'
|
5
|
+
|
6
|
+
module Flipper
|
7
|
+
module Adapters
|
8
|
+
class Poll
|
9
|
+
class Poller
|
10
|
+
PREFIX = "[flipper http async poll adapter]".freeze
|
11
|
+
|
12
|
+
attr_reader :thread, :pid, :mutex, :logger, :interval, :last_synced_at
|
13
|
+
|
14
|
+
def self.instances
|
15
|
+
@instances ||= Concurrent::Map.new
|
16
|
+
end
|
17
|
+
private_class_method :instances
|
18
|
+
|
19
|
+
def self.get(key, options = {})
|
20
|
+
instances.compute_if_absent(key) { new(options) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.reset
|
24
|
+
instances.clear
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(options = {})
|
28
|
+
@thread = nil
|
29
|
+
@pid = Process.pid
|
30
|
+
@mutex = Mutex.new
|
31
|
+
@adapter = Memory.new
|
32
|
+
@remote_adapter = options.fetch(:remote_adapter)
|
33
|
+
@logger = options.fetch(:logger) { Logger.new(STDOUT) }
|
34
|
+
@interval = options.fetch(:interval, 10).to_f
|
35
|
+
@lock = Concurrent::ReadWriteLock.new
|
36
|
+
@last_synced_at = Concurrent::AtomicFixnum.new(0)
|
37
|
+
|
38
|
+
if @interval < 1
|
39
|
+
warn "#{PREFIX} interval must be greater than or equal to 1 but was #{@interval}. Setting @interval to 1."
|
40
|
+
@interval = 1
|
41
|
+
end
|
42
|
+
|
43
|
+
@start_automatically = options.fetch(:start_automatically, true)
|
44
|
+
|
45
|
+
if options.fetch(:shutdown_automatically, true)
|
46
|
+
at_exit { stop }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def adapter
|
51
|
+
@lock.with_read_lock { Memory.new(@adapter.get_all.dup) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def start
|
55
|
+
reset if forked?
|
56
|
+
ensure_worker_running
|
57
|
+
end
|
58
|
+
|
59
|
+
def stop
|
60
|
+
logger.debug { "#{PREFIX} Stopping worker" }
|
61
|
+
@thread&.kill
|
62
|
+
end
|
63
|
+
|
64
|
+
def run
|
65
|
+
loop do
|
66
|
+
sleep jitter
|
67
|
+
start = Concurrent.monotonic_time
|
68
|
+
begin
|
69
|
+
logger.debug { "#{PREFIX} Making a checkity checkity" }
|
70
|
+
|
71
|
+
adapter = Memory.new
|
72
|
+
adapter.import(@remote_adapter)
|
73
|
+
|
74
|
+
@lock.with_write_lock { @adapter.import(adapter) }
|
75
|
+
@last_synced_at.update { |time| Concurrent.monotonic_time }
|
76
|
+
rescue => exception
|
77
|
+
logger.debug { "#{PREFIX} Exception: #{exception.inspect}" }
|
78
|
+
end
|
79
|
+
|
80
|
+
sleep_interval = interval - (Concurrent.monotonic_time - start)
|
81
|
+
sleep sleep_interval if sleep_interval.positive?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def jitter
|
88
|
+
rand
|
89
|
+
end
|
90
|
+
|
91
|
+
def forked?
|
92
|
+
pid != Process.pid
|
93
|
+
end
|
94
|
+
|
95
|
+
def ensure_worker_running
|
96
|
+
# Return early if thread is alive and avoid the mutex lock and unlock.
|
97
|
+
return if thread_alive?
|
98
|
+
|
99
|
+
# If another thread is starting worker thread, then return early so this
|
100
|
+
# thread can enqueue and move on with life.
|
101
|
+
return unless mutex.try_lock
|
102
|
+
|
103
|
+
begin
|
104
|
+
return if thread_alive?
|
105
|
+
@thread = Thread.new { run }
|
106
|
+
logger.debug { "#{PREFIX} Worker thread [#{@thread.object_id}] started" }
|
107
|
+
ensure
|
108
|
+
mutex.unlock
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def thread_alive?
|
113
|
+
@thread && @thread.alive?
|
114
|
+
end
|
115
|
+
|
116
|
+
def reset
|
117
|
+
@pid = Process.pid
|
118
|
+
mutex.unlock if mutex.locked?
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'flipper/adapters/sync/synchronizer'
|
2
|
+
|
3
|
+
module Flipper
|
4
|
+
module Adapters
|
5
|
+
class Poll
|
6
|
+
extend Forwardable
|
7
|
+
include ::Flipper::Adapter
|
8
|
+
|
9
|
+
# Public: The name of the adapter.
|
10
|
+
attr_reader :name, :adapter, :poller
|
11
|
+
|
12
|
+
def_delegators :synced_adapter, :features, :get, :get_multi, :get_all, :add, :remove, :clear, :enable, :disable
|
13
|
+
|
14
|
+
def initialize(poller, adapter)
|
15
|
+
@name = :poll
|
16
|
+
@adapter = adapter
|
17
|
+
@poller = poller
|
18
|
+
@last_synced_at = 0
|
19
|
+
@poller.start
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def synced_adapter
|
25
|
+
@poller.start
|
26
|
+
poller_last_synced_at = @poller.last_synced_at.value
|
27
|
+
if poller_last_synced_at > @last_synced_at
|
28
|
+
Flipper::Adapters::Sync::Synchronizer.new(@adapter, @poller.adapter).call
|
29
|
+
@last_synced_at = poller_last_synced_at
|
30
|
+
end
|
31
|
+
@adapter
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/flipper/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -22,7 +22,7 @@ Dir[FlipperRoot.join('spec/support/**/*.rb')].sort.each { |f| require f }
|
|
22
22
|
|
23
23
|
RSpec.configure do |config|
|
24
24
|
config.before(:example) do
|
25
|
-
Flipper::
|
25
|
+
Flipper::Adapters::Poll::Poller.reset if defined?(Flipper::Adapters::Poll::Poller)
|
26
26
|
Flipper.unregister_groups
|
27
27
|
Flipper.configuration = nil
|
28
28
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
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-
|
12
|
-
dependencies:
|
11
|
+
date: 2022-11-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: concurrent-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "<"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "<"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2'
|
13
27
|
description:
|
14
28
|
email:
|
15
29
|
- nunemaker@gmail.com
|
@@ -68,6 +82,8 @@ files:
|
|
68
82
|
- lib/flipper/adapters/memoizable.rb
|
69
83
|
- lib/flipper/adapters/memory.rb
|
70
84
|
- lib/flipper/adapters/operation_logger.rb
|
85
|
+
- lib/flipper/adapters/poll.rb
|
86
|
+
- lib/flipper/adapters/poll/poller.rb
|
71
87
|
- lib/flipper/adapters/pstore.rb
|
72
88
|
- lib/flipper/adapters/read_only.rb
|
73
89
|
- lib/flipper/adapters/sync.rb
|
@@ -179,9 +195,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
179
195
|
version: '0'
|
180
196
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
197
|
requirements:
|
182
|
-
- - "
|
198
|
+
- - ">"
|
183
199
|
- !ruby/object:Gem::Version
|
184
|
-
version:
|
200
|
+
version: 1.3.1
|
185
201
|
requirements: []
|
186
202
|
rubygems_version: 3.3.7
|
187
203
|
signing_key:
|