semian 0.4.0 → 0.4.1

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: 9df1d9d29629650b74dab6ead2cc8d288de28d78
4
- data.tar.gz: 8752cce5af3858930ee820eab7c2f1c558eeed22
3
+ metadata.gz: 6d26f3db6e9a869dda06d6c9de1b6d450ce50659
4
+ data.tar.gz: 101fb40d19d110414db888954715e8dd2dfd9f22
5
5
  SHA512:
6
- metadata.gz: 2070b61bb3ac7080c36eaba3c0508eb81928b32111dd11e6f5d9668b78fada81549f2eac75f3021787ce03fd30b6f3c5f01a4f5f99d077b0b3aa9aeecc5a3e9d
7
- data.tar.gz: 63f9400b70e1bf039819bb26accf5ecbcea87ab1fb938ff0abaf8e44ccfbbd78e016c3ff48832960cab6fb1c9428785da0f4c2333d15c651b2647bf99d9ae41d
6
+ metadata.gz: c3ffb155d0b7e026944a0eee7dfa47983c42a88ae9dc0781729a27f7f8b34933f3fd257470ef30ee385c07c3746d7da1ac75170955cc7edfdf42a43e7e0d848d
7
+ data.tar.gz: 3264158b8d95db9d254d22093856eaeeaf9388941fc5f235606c038c548b8605cc24661f52a545c730745952c171f3770c30f4f7f41db101fb892d24f8a1d9c6
@@ -1,3 +1,6 @@
1
+ # v0.4.1
2
+ * resource: cast float ticket count to fixnum #75
3
+
1
4
  # v0.4.0
2
5
 
3
6
  * net/http: add adapter for net/http #58
data/README.md CHANGED
@@ -130,12 +130,13 @@ client = Redis.new(semian: {
130
130
  #### Net::HTTP
131
131
  For the `Net::HTTP` specific Semian adapter, since many external libraries may create
132
132
  HTTP connections on the user's behalf, the parameters are instead provided
133
- by calling specific functions in `Semian::NetHTTP`, perhaps in an initialization file.
133
+ by associating callback functions with `Semian::NetHTTP`, perhaps in an initialization file.
134
134
 
135
135
  ##### Naming and Options
136
136
  To give Semian parameters, assign a `proc` to `Semian::NetHTTP.semian_configuration`
137
- that takes a two parameters, `host` and `port` like `127.0.0.1` and `80` or `github_com` and `80`,
138
- and returns a `Hash` with keys as follows.
137
+ that takes a two parameters, `host` and `port` like `127.0.0.1`,`443` or `github_com`,`80`,
138
+ and returns a `Hash` with configuration parameters as follows. The `proc` is used as a
139
+ callback to initialize the configuration options, similar to other adapters.
139
140
 
140
141
  ```ruby
141
142
  SEMIAN_PARAMETERS = { tickets: 1,
@@ -161,6 +162,11 @@ The `semian_options` passed apply to that resource. Semian creates the `semian_i
161
162
  from the `name` to look up and store changes in the circuit breaker and bulkhead states
162
163
  and associate successes, failures, errors with the protected resource.
163
164
 
165
+ We only require that:
166
+ * the `semian_configuration` be **set only once** over the lifetime of the library
167
+ * the output of the `proc` be the same over time, that is, the configuration produced by
168
+ each pair of `host`, `port` is **the same each time** the callback is invoked.
169
+
164
170
  For most purposes, `"#{host}_#{port}"` is a good default `name`. Custom `name` formats
165
171
  can be useful to grouping related subdomains as one resource, so that they all
166
172
  contribute to the same circuit breaker and bulkhead state and fail together.
@@ -560,7 +566,7 @@ non-IO.
560
566
  [redis-semian-adapter]: lib/semian/redis.rb
561
567
  [semian-adapter]: lib/semian/adapter.rb
562
568
  [nethttp-semian-adapter]: lib/semian/net_http.rb
563
- [nethttp-default-errors]: lib/semian/net_http.rb#L33-L43
569
+ [nethttp-default-errors]: lib/semian/net_http.rb#L35-L45
564
570
  [semian-instrumentable]: lib/semian/instrumentable.rb
565
571
  [statsd-instrument]: http://github.com/shopify/statsd-instrument
566
572
  [resiliency-blog-post]: http://www.shopify.com/technology/16906928-building-and-testing-resilient-ruby-on-rails-applications
@@ -283,6 +283,10 @@ semian_resource_initialize(VALUE self, VALUE id, VALUE tickets, VALUE permission
283
283
  if (TYPE(id) != T_SYMBOL && TYPE(id) != T_STRING) {
284
284
  rb_raise(rb_eTypeError, "id must be a symbol or string");
285
285
  }
286
+ if (TYPE(tickets) == T_FLOAT) {
287
+ rb_warn("semian ticket value %f is a float, converting to fixnum", RFLOAT_VALUE(tickets));
288
+ tickets = INT2FIX((int) RFLOAT_VALUE(tickets));
289
+ }
286
290
  Check_Type(tickets, T_FIXNUM);
287
291
  Check_Type(permissions, T_FIXNUM);
288
292
  if (TYPE(default_timeout) != T_FIXNUM && TYPE(default_timeout) != T_FLOAT) {
@@ -22,12 +22,14 @@ module Semian
22
22
  ResourceBusyError = ::Net::ResourceBusyError
23
23
  CircuitOpenError = ::Net::CircuitOpenError
24
24
 
25
- def semian_configuration
26
- Semian::NetHTTP.retrieve_semian_configuration(address, port)
25
+ class SemianConfigurationChangedError < RuntimeError
26
+ def initialize(msg = "Cannot re-initialize semian_configuration")
27
+ super
28
+ end
27
29
  end
28
30
 
29
31
  def semian_identifier
30
- "nethttp_#{semian_configuration[:name]}"
32
+ "nethttp_#{raw_semian_options[:name]}"
31
33
  end
32
34
 
33
35
  DEFAULT_ERRORS = [
@@ -52,8 +54,13 @@ module Semian
52
54
  end
53
55
 
54
56
  class << self
55
- attr_accessor :semian_configuration
56
57
  attr_accessor :exceptions
58
+ attr_reader :semian_configuration
59
+
60
+ def semian_configuration=(configuration)
61
+ raise Semian::NetHTTP::SemianConfigurationChangedError unless @semian_configuration.nil?
62
+ @semian_configuration = configuration
63
+ end
57
64
 
58
65
  def retrieve_semian_configuration(host, port)
59
66
  @semian_configuration.call(host, port) if @semian_configuration.respond_to?(:call)
@@ -67,9 +74,10 @@ module Semian
67
74
  Semian::NetHTTP.reset_exceptions
68
75
 
69
76
  def raw_semian_options
70
- options = semian_configuration
71
- options = options.dup unless options.nil?
72
- options
77
+ @raw_semian_options ||= begin
78
+ @raw_semian_options = Semian::NetHTTP.retrieve_semian_configuration(address, port)
79
+ @raw_semian_options = @raw_semian_options.dup unless @raw_semian_options.nil?
80
+ end
73
81
  end
74
82
 
75
83
  def resource_exceptions
@@ -77,7 +85,7 @@ module Semian
77
85
  end
78
86
 
79
87
  def disabled?
80
- semian_configuration.nil?
88
+ raw_semian_options.nil?
81
89
  end
82
90
 
83
91
  def connect
@@ -1,6 +1,6 @@
1
1
  module Semian
2
2
  # This class acts as a replacement for `ProtectedResource` when
3
- # the semian configuration of an `Adatper` is missing or explicitly disabled
3
+ # the semian configuration of an `Adapter` is missing or explicitly disabled
4
4
  class UnprotectedResource
5
5
  attr_reader :name
6
6
 
@@ -1,3 +1,3 @@
1
1
  module Semian
2
- VERSION = '0.4.0'
2
+ VERSION = '0.4.1'
3
3
  end
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.files = `git ls-files`.split("\n")
20
20
  s.extensions = ['ext/semian/extconf.rb']
21
21
  s.add_development_dependency 'rake-compiler', '~> 0.9'
22
+ s.add_development_dependency 'rake', '< 11.0'
22
23
  s.add_development_dependency 'timecop'
23
24
  s.add_development_dependency 'mysql2'
24
25
  s.add_development_dependency 'redis'
@@ -21,6 +21,7 @@ class TestNetHTTP < MiniTest::Unit::TestCase
21
21
  error_timeout: 10,
22
22
  }.freeze
23
23
  DEFAULT_SEMIAN_CONFIGURATION = proc do |host, port|
24
+ next nil if host == "127.0.0.1" && port == 8474 # disable if toxiproxy
24
25
  DEFAULT_SEMIAN_OPTIONS.merge(name: "#{host}_#{port}")
25
26
  end
26
27
 
@@ -191,6 +192,17 @@ class TestNetHTTP < MiniTest::Unit::TestCase
191
192
  end
192
193
  end
193
194
 
195
+ def test_custom_raw_semian_options_can_only_assign_once
196
+ semian_configuration_proc = proc do |host, port|
197
+ DEFAULT_SEMIAN_OPTIONS.merge(name: "#{host}_#{port}")
198
+ end
199
+ with_semian_configuration(semian_configuration_proc) do
200
+ assert_raises(Semian::NetHTTP::SemianConfigurationChangedError) do
201
+ Semian::NetHTTP.semian_configuration = semian_configuration_proc
202
+ end
203
+ end
204
+ end
205
+
194
206
  def test_custom_raw_semian_options_work_with_default_fallback
195
207
  with_server do
196
208
  semian_config = {}
@@ -230,7 +242,8 @@ class TestNetHTTP < MiniTest::Unit::TestCase
230
242
  semian_config["development"]["nethttp_default"] = DEFAULT_SEMIAN_OPTIONS
231
243
  sample_env = "development"
232
244
 
233
- semian_configuration_proc = proc do
245
+ semian_configuration_proc = proc do |host, port|
246
+ next nil if host == "127.0.0.1" && port == 8474 # # disable if toxiproxy
234
247
  semian_identifier = "nethttp_default"
235
248
  semian_config[sample_env][semian_identifier].merge(name: "default")
236
249
  end
@@ -344,10 +357,31 @@ class TestNetHTTP < MiniTest::Unit::TestCase
344
357
 
345
358
  def with_semian_configuration(options = DEFAULT_SEMIAN_CONFIGURATION)
346
359
  orig_semian_options = Semian::NetHTTP.semian_configuration
360
+ Semian::NetHTTP.instance_variable_set(:@semian_configuration, nil)
361
+ mutated_objects = {}
362
+ Semian::NetHTTP.send(:alias_method, :orig_semian_resource, :semian_resource)
363
+ Semian::NetHTTP.send(:alias_method, :orig_raw_semian_options, :raw_semian_options)
364
+ Semian::NetHTTP.send(:define_method, :semian_resource) do
365
+ mutated_objects[self] = [@semian_resource, @raw_semian_options] unless mutated_objects.key?(self)
366
+ orig_semian_resource
367
+ end
368
+ Semian::NetHTTP.send(:define_method, :raw_semian_options) do
369
+ mutated_objects[self] = [@semian_resource, @raw_semian_options] unless mutated_objects.key?(self)
370
+ orig_raw_semian_options
371
+ end
372
+
347
373
  Semian::NetHTTP.semian_configuration = options
348
374
  yield
349
375
  ensure
376
+ Semian::NetHTTP.instance_variable_set(:@semian_configuration, nil)
350
377
  Semian::NetHTTP.semian_configuration = orig_semian_options
378
+ Semian::NetHTTP.send(:alias_method, :semian_resource, :orig_semian_resource)
379
+ Semian::NetHTTP.send(:alias_method, :raw_semian_options, :orig_raw_semian_options)
380
+ Semian::NetHTTP.send(:undef_method, :orig_semian_resource, :orig_raw_semian_options)
381
+ mutated_objects.each do |instance, (res, opt)| # Sadly, only way to fully restore cached properties
382
+ instance.instance_variable_set(:@semian_resource, res)
383
+ instance.instance_variable_set(:@raw_semian_options, opt)
384
+ end
351
385
  end
352
386
 
353
387
  def with_custom_errors(errors)
@@ -26,6 +26,12 @@ class TestResource < MiniTest::Unit::TestCase
26
26
  end
27
27
  end
28
28
 
29
+ def test_initialize_with_float
30
+ resource = create_resource :testing, tickets: 1.0
31
+ assert resource
32
+ assert_equal 1, resource.tickets
33
+ end
34
+
29
35
  def test_max_tickets
30
36
  assert Semian::MAX_TICKETS > 0
31
37
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semian
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Francis
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-11-26 00:00:00.000000000 Z
12
+ date: 2016-03-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler
@@ -25,6 +25,20 @@ dependencies:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0.9'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "<"
33
+ - !ruby/object:Gem::Version
34
+ version: '11.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '11.0'
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: timecop
30
44
  requirement: !ruby/object:Gem::Requirement