prefab-cloud-ruby 0.0.18 → 0.0.19

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
  SHA1:
3
- metadata.gz: 1f4b5d7fb7e15da13eaf3e2fb5891b4aa89604db
4
- data.tar.gz: '0779901b0789060861efafd813b28c06e1107ed4'
3
+ metadata.gz: 2d4da69f7090effaacca738be0a70baec8e2c8d0
4
+ data.tar.gz: 42b6de32dbefaa8f23ef024a4b7b8250d78d2c48
5
5
  SHA512:
6
- metadata.gz: '09d6907355402ffaddc9e757ac159e0172c5a227aa24793aa583326291f3590fa100f59b0bec36e4fca3605c054f47defd7da466c5244c209b28d0392a7c6283'
7
- data.tar.gz: 7b3e1ce5ca388374a065fae0106abf52d155cbbfd1e61967ae38d28cb88cee5763226fa88c4c9fc4b60c99d212b1e69908f0c245d1131b142ec9beef9a6bd05d
6
+ metadata.gz: 70ef17720139c952bdfdfa3938578c69365554155f20687bee068e5d3715b811394932e548b31673529448321b76f6c8892eec21dcaacd41fc4031ab63f9fb66
7
+ data.tar.gz: 85fddf3468abde394bada8b5404935e213bd52f193f0cc6e0abb04d34c5c6ad8b55c4fb83ab83d3234663f649354158aca1fb4c14a897dfb1477ad43e2926204
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.18
1
+ 0.0.19
data/lib/prefab/client.rb CHANGED
@@ -80,11 +80,15 @@ module Prefab
80
80
  end
81
81
  end
82
82
 
83
+ def cache_key(post_fix)
84
+ "prefab:#{account_id}:#{post_fix}"
85
+ end
86
+
83
87
  private
84
88
 
85
89
  def reset!
86
90
  @stubs.clear
87
- reset_channel!
91
+ @_channel = nil
88
92
  end
89
93
 
90
94
  def stub_for(service, timeout)
@@ -1,17 +1,16 @@
1
1
  module Prefab
2
2
  class ConfigClient
3
3
  RECONNECT_WAIT = 5
4
- CHECKPOINT_LOCK = 20
4
+ SUSPENDERS_RESET_LOCK_SEC = 20
5
5
  DEFAULT_CHECKPOINT_FREQ_SEC = 10
6
- DEFAULT_MAX_CHECKPOINT_AGE_SEC = 60
6
+ DEFAULT_MAX_SUSPENDERS_AGE_SEC = 60
7
7
 
8
8
  def initialize(base_client, timeout)
9
9
  @base_client = base_client
10
10
  @timeout = timeout
11
11
  @initialization_lock = Concurrent::ReadWriteLock.new
12
12
 
13
- @checkpoint_max_age_secs = (ENV["PREFAB_CHECKPOINT_MAX_AGE_SEC"] || DEFAULT_MAX_CHECKPOINT_AGE_SEC)
14
- @checkpoint_max_age = @checkpoint_max_age_secs * 1000 * 10000
13
+ @suspenders_max_age_secs = (ENV["PREFAB_SUSPENDERS_MAX_AGE_SEC"] || DEFAULT_MAX_SUSPENDERS_AGE_SEC)
15
14
  @checkpoint_freq_secs = (ENV["PREFAB_DEFAULT_CHECKPOINT_FREQ_SEC"] || DEFAULT_CHECKPOINT_FREQ_SEC)
16
15
 
17
16
  @config_loader = Prefab::ConfigLoader.new(@base_client)
@@ -19,7 +18,9 @@ module Prefab
19
18
 
20
19
  @initialization_lock.acquire_write_lock
21
20
 
22
- start_checkpointing_thread
21
+ load_or_save_checkpoint
22
+ ensure_api_connection_started
23
+ start_checkpointing_thread if has_real_cache?
23
24
  end
24
25
 
25
26
  def get(prop)
@@ -29,14 +30,14 @@ module Prefab
29
30
  end
30
31
 
31
32
  def upsert(key, config_value, namespace = nil, previous_key = nil)
32
- raise "key must not contain ':' set namespaces separately" if key.include? ":"
33
- raise "namespace must not contain ':'" if namespace&.include?(":")
33
+ raise "Key must not contain ':' set namespaces separately" if key.include? ":"
34
+ raise "Namespace must not contain ':'" if namespace&.include?(":")
34
35
  config_delta = Prefab::ConfigClient.value_to_delta(key, config_value, namespace)
35
36
  upsert_req = Prefab::UpsertRequest.new(config_delta: config_delta)
36
37
  upsert_req.previous_key = previous_key if previous_key&.present?
37
38
 
38
39
  @base_client.request Prefab::ConfigService, :upsert, req_options: { timeout: @timeout }, params: upsert_req
39
-
40
+ @base_client.stats.increment("prefab.config.upsert")
40
41
  @config_loader.set(config_delta)
41
42
  @config_loader.rm(previous_key) if previous_key&.present?
42
43
  @config_resolver.update
@@ -76,6 +77,7 @@ module Prefab
76
77
  @config_loader.set(delta)
77
78
  end
78
79
  @base_client.log_internal Logger::INFO, "Found checkpoint with highwater id #{@config_loader.highwater_mark}"
80
+ @base_client.stats.increment("prefab.config.checkpoint.load")
79
81
  @config_resolver.update
80
82
  finish_init!
81
83
  else
@@ -91,6 +93,7 @@ module Prefab
91
93
  @base_client.log_internal Logger::DEBUG, "Save Checkpoint #{@config_loader.highwater_mark} Thread #{Thread.current.object_id}"
92
94
  @base_client.shared_cache.write(checkpoint_cache_key, Prefab::ConfigDeltas.encode(deltas))
93
95
  @base_client.shared_cache.write(checkpoint_highwater_cache_key, @config_loader.highwater_mark)
96
+ @base_client.stats.increment("prefab.config.checkpoint.save")
94
97
  rescue StandardError => exn
95
98
  @base_client.log_internal Logger::INFO, "Issue Saving Checkpoint #{exn.message}"
96
99
  end
@@ -101,7 +104,9 @@ module Prefab
101
104
  Thread.new do
102
105
  loop do
103
106
  begin
104
- checkpoint_if_needed
107
+ load_or_save_checkpoint
108
+
109
+ suspenders_if_needed
105
110
 
106
111
  started_at = Time.now
107
112
  delta = @checkpoint_freq_secs - (Time.now - started_at)
@@ -120,9 +125,9 @@ module Prefab
120
125
  # if it is lower than our own highwater mark, save a checkpoint
121
126
  # if everything is up to date, but the shared highwater mark is old, coordinate amongst other processes to have
122
127
  # one process "double check" by restarting the API thread
123
- def checkpoint_if_needed
128
+ def load_or_save_checkpoint
124
129
  shared_highwater_mark = get_shared_highwater_mark
125
- @base_client.log_internal Logger::DEBUG, "Checkpoint_if_needed apx ahead/behind #{(@config_loader.highwater_mark - shared_highwater_mark) / (1000 * 10000)}"
130
+ @base_client.log_internal Logger::DEBUG, "Checkpoint_if_needed highwater apx ahead/behind #{(@config_loader.highwater_mark - shared_highwater_mark) / (1000 * 10000)}"
126
131
 
127
132
  if shared_highwater_mark > @config_loader.highwater_mark
128
133
  @base_client.log_internal Logger::DEBUG, "We were behind, loading checkpoint"
@@ -130,40 +135,52 @@ module Prefab
130
135
  elsif shared_highwater_mark < @config_loader.highwater_mark
131
136
  @base_client.log_internal Logger::DEBUG, "Saving off checkpoint"
132
137
  save_checkpoint
133
- elsif shared_highwater_is_old?
138
+ end
139
+ end
140
+
141
+ def suspenders_if_needed
142
+ if suspenders_age_is_old?
134
143
  if get_shared_lock?
135
- @base_client.log_internal Logger::DEBUG, "Shared highwater mark > PREFAB_CHECKPOINT_MAX_AGE #{@checkpoint_max_age_secs}. We have been chosen to run suspenders"
144
+ @base_client.log_internal Logger::DEBUG, "Suspenders > PREFAB_SUSPENDERS_MAX_AGE_SEC #{@suspenders_max_age_secs}. We have been chosen to run suspenders"
136
145
  reset_api_connection
137
146
  else
138
- @base_client.log_internal Logger::DEBUG, "Shared highwater mark > PREFAB_CHECKPOINT_MAX_AGE #{@checkpoint_max_age_secs}. Other process is running suspenders"
147
+ @base_client.log_internal Logger::DEBUG, "Suspenders > PREFAB_SUSPENDERS_MAX_AGE_SEC #{@suspenders_max_age_secs}. Other process is running suspenders"
139
148
  end
140
149
  end
141
150
  end
142
151
 
143
- def current_time_as_id
144
- Time.now.to_f * 1000 * 10000
145
- end
146
-
147
- def shared_highwater_is_old?
148
- age = current_time_as_id - get_shared_highwater_mark
149
- @base_client.log_internal Logger::DEBUG, "shared_highwater_is_old? apx #{age / (1000 * 10000)}" if age > @checkpoint_max_age
150
- age > @checkpoint_max_age_secs
152
+ def suspenders_age_is_old?
153
+ age = Time.now.to_i - get_checkpoint_suspenders
154
+ @base_client.log_internal Logger::DEBUG, "checkpoint_suspenders_is_old? apx #{age}" if age > @suspenders_max_age_secs
155
+ age > @suspenders_max_age_secs
151
156
  end
152
157
 
153
158
  def get_shared_highwater_mark
154
159
  (@base_client.shared_cache.read(checkpoint_highwater_cache_key) || 0).to_i
155
160
  end
156
161
 
162
+ def get_checkpoint_suspenders
163
+ (@base_client.shared_cache.read(suspenders_last_run_cache_key) || 0).to_i
164
+ end
165
+
166
+ def set_suspenders
167
+ @base_client.shared_cache.write(suspenders_last_run_cache_key, Time.now.to_i)
168
+ end
169
+
157
170
  def get_shared_lock?
158
- in_progess = @base_client.shared_cache.read(checkpoint_update_in_progress_cache_key)
171
+ in_progess = @base_client.shared_cache.read(suspenders_reset_in_progress_cache_key)
159
172
  if in_progess.nil?
160
- @base_client.shared_cache.write(checkpoint_update_in_progress_cache_key, "true", { expires_in: CHECKPOINT_LOCK })
173
+ @base_client.shared_cache.write(suspenders_reset_in_progress_cache_key, "true", { expires_in: SUSPENDERS_RESET_LOCK_SEC })
161
174
  true
162
175
  else
163
176
  false
164
177
  end
165
178
  end
166
179
 
180
+ def ensure_api_connection_started
181
+ reset_api_connection if @api_connection_thread.nil?
182
+ end
183
+
167
184
  def reset_api_connection
168
185
  @api_connection_thread&.exit
169
186
  start_api_connection_thread(@config_loader.highwater_mark)
@@ -182,6 +199,8 @@ module Prefab
182
199
  config_req = Prefab::ConfigServicePointer.new(account_id: @base_client.account_id,
183
200
  start_at_id: start_at_id)
184
201
  @base_client.log_internal Logger::DEBUG, "start api connection thread #{start_at_id}"
202
+ @base_client.stats.increment("prefab.config.api.start")
203
+ set_suspenders
185
204
  @api_connection_thread = Thread.new do
186
205
  while true do
187
206
  begin
@@ -202,16 +221,24 @@ module Prefab
202
221
  end
203
222
  end
204
223
 
224
+ def has_real_cache?
225
+ @base_client.shared_cache.class != NoopCache
226
+ end
227
+
205
228
  def checkpoint_cache_key
206
- "prefab:config:checkpoint"
229
+ @base_client.cache_key "config:checkpoint"
207
230
  end
208
231
 
209
- def checkpoint_update_in_progress_cache_key
210
- "prefab:config:checkpoint:updating"
232
+ def suspenders_reset_in_progress_cache_key
233
+ @base_client.cache_key "config:checkpoint:updating"
211
234
  end
212
235
 
213
236
  def checkpoint_highwater_cache_key
214
- "prefab:config:checkpoint:highwater"
237
+ @base_client.cache_key "config:checkpoint:highwater"
238
+ end
239
+
240
+ def suspenders_last_run_cache_key
241
+ @base_client.cache_key "config:checkpoint:suspenders"
215
242
  end
216
243
  end
217
244
  end
@@ -21,6 +21,11 @@ module Prefab
21
21
  end
22
22
 
23
23
  def set(delta)
24
+ # don't overwrite newer values
25
+ if @api_config[delta.key] && @api_config[delta.key].id > delta.id
26
+ return
27
+ end
28
+
24
29
  if delta.value.nil?
25
30
  @api_config.delete(delta.key)
26
31
  else
@@ -2,7 +2,7 @@ module Prefab
2
2
 
3
3
  class NoopStats
4
4
  # receives increment("prefab.ratelimit.limitcheck", {:tags=>["policy_group:page_view", "pass:true"]})
5
- def increment(name, opts)
5
+ def increment(name, opts={})
6
6
  end
7
7
  end
8
8
  end
@@ -39,7 +39,7 @@ module Prefab
39
39
  handle_error(e, on_error, groups)
40
40
  end
41
41
 
42
- def upsert(group, policy_name, limit, burst: nil)
42
+ def upsert(group, policy_name, limit, burst: nil, safety_level: nil)
43
43
  burst = limit if burst.nil?
44
44
  limit_defintion = Prefab::LimitDefinition.new(
45
45
  account_id: @base_client.account_id,
@@ -48,6 +48,10 @@ module Prefab
48
48
  limit: limit,
49
49
  burst: burst
50
50
  )
51
+ unless safety_level.nil?
52
+ limit_defintion.safety_level = safety_level
53
+ end
54
+
51
55
  @base_client.request Prefab::RateLimitService, :upsert_limit_definition, params: limit_defintion
52
56
  end
53
57
 
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: prefab-cloud-ruby 0.0.18 ruby lib
5
+ # stub: prefab-cloud-ruby 0.0.19 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "prefab-cloud-ruby".freeze
9
- s.version = "0.0.18"
9
+ s.version = "0.0.19"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Jeff Dwyer".freeze]
14
- s.date = "2018-03-12"
14
+ s.date = "2018-04-09"
15
15
  s.description = "RateLimits & Config as a service".freeze
16
16
  s.email = "jdwyer@prefab.cloud".freeze
17
17
  s.extra_rdoc_files = [
@@ -25,6 +25,23 @@ class TestConfigLoader < Minitest::Test
25
25
  assert_equal 5, @loader.highwater_mark
26
26
  end
27
27
 
28
+
29
+
30
+ def test_keeps_most_recent
31
+ assert_equal 0, @loader.highwater_mark
32
+ @loader.set(Prefab::ConfigDelta.new(id: 1, key: "sample_int", value: Prefab::ConfigValue.new(int: 1)))
33
+ assert_equal 1, @loader.highwater_mark
34
+ should_be :int, 1, "sample_int"
35
+
36
+ @loader.set(Prefab::ConfigDelta.new(id: 4, key: "sample_int", value: Prefab::ConfigValue.new(int: 4)))
37
+ assert_equal 4, @loader.highwater_mark
38
+ should_be :int, 4, "sample_int"
39
+
40
+ @loader.set(Prefab::ConfigDelta.new(id: 2, key: "sample_int", value: Prefab::ConfigValue.new(int: 2)))
41
+ assert_equal 4, @loader.highwater_mark
42
+ should_be :int, 4, "sample_int"
43
+ end
44
+
28
45
  def test_api_precedence
29
46
  should_be :int, 123, "sample_int"
30
47
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prefab-cloud-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.18
4
+ version: 0.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Dwyer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-12 00:00:00.000000000 Z
11
+ date: 2018-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grpc