prefab-cloud-ruby 0.0.18 → 0.0.19

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
  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