semian 0.14.0 → 0.16.0

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
  SHA256:
3
- metadata.gz: a7b62deafc4e8de524ae8aec32a17e3a1065d70206a5ead2ef6298da3b1c38ed
4
- data.tar.gz: 3f6b18aa473410c0ad8d476931417fa69595328fd748a2edb75a333709b901cd
3
+ metadata.gz: 03aa7b6a715e0990279468f71a5bacbd03b94f983c16083570a09dc46c69d325
4
+ data.tar.gz: 1b53f85622bfa3868585ea8836df867a37da5b4142b769ad8b968d9865c001c2
5
5
  SHA512:
6
- metadata.gz: c064829103c0c4f8915f6c072d43872b9a6dc011987e6a81f5efa8931052cc84b758df9bc4dd74f4f90c0501accbaa3e09ca3212af6a8a3e7056ce1f28a28e22
7
- data.tar.gz: 124128fc2a5791317ea5a04b32c84e9b3cd394e843a74599c5ecf044cc6c89eec656384675b88e9fd73e95038dfb1e8a35b8e613034114e264b59e754a8eec0c
6
+ metadata.gz: f7f481a7a77c6d91574500e2a636eb6bd9721e61be5c8740265f58ac90895525ed9b34750b7dbb23d97360a3449a7a990994d870c8a9730e8d06350afda7c7de
7
+ data.tar.gz: 216189dea6814080db529843164dd02235541127ce9058ff803cc3843842220e87340b45a73109a2004d6205194b166b0cbcbf55e46601a5bf5f00c75cb5678c
data/README.md CHANGED
@@ -211,7 +211,7 @@ calculate and adjust ticket counts.
211
211
 
212
212
  **Note**:
213
213
 
214
- - You must pass **exactly** one of ticket or quota.
214
+ - You must pass **exactly** one of options: `tickets` or `quota`.
215
215
  - Tickets available will be the ceiling of the quota ratio to the number of workers
216
216
  - So, with one worker, there will always be a minimum of 1 ticket
217
217
  - Workers in different processes will automatically unregister when the process exits.
@@ -236,7 +236,7 @@ SEMIAN_PARAMETERS = { tickets: 1,
236
236
  error_timeout: 10 }
237
237
  Semian::NetHTTP.semian_configuration = proc do |host, port|
238
238
  # Let's make it only active for github.com
239
- if host == "github.com" && port == "80"
239
+ if host == "github.com" && port.to_i == 80
240
240
  SEMIAN_PARAMETERS.merge(name: "github.com_80")
241
241
  else
242
242
  nil
@@ -282,19 +282,22 @@ Semian::NetHTTP.exceptions += [::OpenSSL::SSL::SSLError]
282
282
  Semian::NetHTTP.reset_exceptions
283
283
  # assert_equal(Semian::NetHTTP.exceptions, Semian::NetHTTP::DEFAULT_ERRORS)
284
284
  ```
285
+
285
286
  ##### Mark Unsuccessful Responses as Failures
286
- Unsuccessful responses (e.g. 5xx responses) do not raise exceptions, and as such are not marked as failures by default. The `open_circuit_server_errors` Semian configuration parameter may be set to enable this behaviour, to mark unsuccessful responses as failures as seen below:
287
+
288
+ Unsuccessful responses (e.g. 5xx responses) do not raise exceptions,
289
+ and as such are not marked as failures by default.
290
+ The `open_circuit_server_errors` Semian configuration parameter may be set to enable this behaviour,
291
+ to mark unsuccessful responses as failures as seen below:
287
292
 
288
293
  ```ruby
289
294
  SEMIAN_PARAMETERS = { tickets: 1,
290
295
  success_threshold: 1,
291
296
  error_threshold: 3,
292
297
  error_timeout: 10,
293
- open_circuit_server_errors: true}
298
+ open_circuit_server_errors: true }
294
299
  ```
295
300
 
296
-
297
-
298
301
  # Understanding Semian
299
302
 
300
303
  Semian is a library with heuristics for failing fast. This section will explain
@@ -415,7 +418,7 @@ response time. This is the problem Semian solves by failing fast.
415
418
 
416
419
  ## How does Semian work?
417
420
 
418
- Semian consists of two parts: circuit breaker and bulkheading. To understand
421
+ Semian consists of two parts: **Circuit breaker** and **Bulkheading**. To understand
419
422
  Semian, and especially how to configure it, we must understand these patterns
420
423
  and their implementation.
421
424
 
@@ -453,6 +456,8 @@ There are four configuration parameters for circuit breakers in Semian:
453
456
  * **error_threshold_timeout**. The amount of time in seconds that error_threshold errors must occur to open the circuit. Defaults to error_timeout seconds if not set.
454
457
  * **error_timeout**. The amount of time in seconds until trying to query the resource
455
458
  again.
459
+ * **error_threshold_timeout_enabled**. If set to false it will disable the time window for evicting old exceptions. `error_timeout` is still used and will reset
460
+ the circuit. Defaults to `true` if not set.
456
461
  * **success_threshold**. The amount of successes on the circuit until closing it
457
462
  again, that is to start accepting all requests to the circuit.
458
463
  * **half_open_resource_timeout**. Timeout for the resource in seconds when the circuit is half-open (supported for MySQL, Net::HTTP and Redis).
@@ -531,7 +536,7 @@ provides an easy way to get the semaphore key:
531
536
 
532
537
  ```
533
538
  irb> require 'semian'
534
- irb> puts Semian::Resource.new(:your_resource_name, tickets:1).key # do this from a dev machine
539
+ irb> puts Semian::Resource.new(:your_resource_name, tickets: 42).key # do this from a dev machine
535
540
  "0x48af51ea"
536
541
  ```
537
542
 
@@ -553,8 +558,8 @@ otime = Thu Mar 30 15:06:16 2017
553
558
  ctime = Mon Mar 13 20:25:36 2017
554
559
  semnum value ncount zcount pid
555
560
  0 1 0 0 48
556
- 1 25 0 0 48
557
- 2 25 0 0 27
561
+ 1 42 0 0 48
562
+ 2 42 0 0 27
558
563
  3 31 0 0 48
559
564
  ```
560
565
 
@@ -754,11 +759,13 @@ non-IO.
754
759
 
755
760
  # Developing Semian
756
761
 
757
- Semian requires a Linux environment. We provide a [docker-compose](https://docs.docker.com/compose/) file
758
- that runs MySQL, Redis, Toxiproxy and Ruby in containers. Use
759
- the steps below to work on Semian from a Mac OS environment.
762
+ Semian requires a Linux environment for **Bulkheading**.
763
+ We provide a [docker-compose](https://docs.docker.com/compose/) file
764
+ that runs MySQL, Redis, Toxiproxy and Ruby in containers.
765
+ Use the steps below to work on Semian from a Mac OS environment.
760
766
 
761
767
  ## Prerequisites :
768
+
762
769
  ```bash
763
770
  # install docker-for-desktop
764
771
  $ brew cask install docker
@@ -819,6 +826,17 @@ $ cd semian
819
826
  $ bundle exec rake test:parallel TEST_WORKERS=5 TEST_WORKER_NUM=1
820
827
  ```
821
828
 
829
+ ### Debug
830
+
831
+ Build a semian native extension with debug information.
832
+
833
+ ```shell
834
+ $ bundle exec rake clean --trace
835
+ $ export DEBUG=1
836
+ $ bundle exec rake build
837
+ $ bundle install
838
+ ```
839
+
822
840
  [hystrix]: https://github.com/Netflix/Hystrix
823
841
  [release-it]: https://pragprog.com/titles/mnee2/release-it-second-edition/
824
842
  [shopify]: http://www.shopify.com/
@@ -273,10 +273,10 @@ static void
273
273
  check_tickets_xor_quota_arg(VALUE tickets, VALUE quota)
274
274
  {
275
275
  if (tickets == Qnil && quota == Qnil) {
276
- rb_raise(rb_eArgError, "Semian configuration require either the :ticket or :quota parameter, you provided neither");
276
+ rb_raise(rb_eArgError, "Semian configuration require either the :tickets or :quota parameter, you provided neither");
277
277
  }
278
278
  if (tickets != Qnil && quota != Qnil) {
279
- rb_raise(rb_eArgError, "Semian configuration require either the :ticket or :quota parameter, you provided both");
279
+ rb_raise(rb_eArgError, "Semian configuration require either the :tickets or :quota parameter, you provided both");
280
280
  }
281
281
  }
282
282
 
@@ -10,6 +10,9 @@ and functions associated directly weth semops.
10
10
  #include <errno.h>
11
11
  #include <stdio.h>
12
12
  #include <string.h>
13
+ #ifdef DEBUG
14
+ #include <unistd.h>
15
+ #endif
13
16
 
14
17
  #include <openssl/sha.h>
15
18
  #include <ruby.h>
@@ -110,7 +113,8 @@ acquire_semaphore_without_gvl(void *p);
110
113
  static inline void
111
114
  print_sem_vals(int sem_id)
112
115
  {
113
- printf("lock %d, tickets: %d configured: %d, registered workers %d\n",
116
+ printf("[pid=%d][semian] semaphore values lock: %d, tickets: %d configured: %d, registered workers: %d\n",
117
+ getpid(),
114
118
  get_sem_val(sem_id, SI_SEM_LOCK),
115
119
  get_sem_val(sem_id, SI_SEM_TICKETS),
116
120
  get_sem_val(sem_id, SI_SEM_CONFIGURED_TICKETS),
@@ -6,16 +6,24 @@ module Semian
6
6
 
7
7
  def_delegators :@state, :closed?, :open?, :half_open?
8
8
 
9
- attr_reader :name, :half_open_resource_timeout, :error_timeout, :state, :last_error
9
+ attr_reader(
10
+ :name,
11
+ :half_open_resource_timeout,
12
+ :error_timeout,
13
+ :state,
14
+ :last_error,
15
+ :error_threshold_timeout_enabled,
16
+ )
10
17
 
11
18
  def initialize(name, exceptions:, success_threshold:, error_threshold:,
12
19
  error_timeout:, implementation:, half_open_resource_timeout: nil,
13
- error_threshold_timeout: nil)
20
+ error_threshold_timeout: nil, error_threshold_timeout_enabled: true)
14
21
 
15
22
  @name = name.to_sym
16
23
  @success_count_threshold = success_threshold
17
24
  @error_count_threshold = error_threshold
18
25
  @error_threshold_timeout = error_threshold_timeout || error_timeout
26
+ @error_threshold_timeout_enabled = error_threshold_timeout_enabled.nil? ? true : error_threshold_timeout_enabled
19
27
  @error_timeout = error_timeout
20
28
  @exceptions = exceptions
21
29
  @half_open_resource_timeout = half_open_resource_timeout
@@ -131,7 +139,10 @@ module Semian
131
139
  end
132
140
 
133
141
  def push_time(window, time: Time.now)
134
- window.reject! { |err_time| err_time + @error_threshold_timeout < time.to_i }
142
+ if error_threshold_timeout_enabled
143
+ window.reject! { |err_time| err_time + @error_threshold_timeout < time.to_i }
144
+ end
145
+
135
146
  window << time.to_i
136
147
  end
137
148
 
data/lib/semian/mysql2.rb CHANGED
@@ -70,6 +70,8 @@ module Semian
70
70
  end
71
71
 
72
72
  def ping
73
+ return false if closed?
74
+
73
75
  result = nil
74
76
  acquire_semian_resource(adapter: :mysql, scope: :ping) do
75
77
  result = raw_ping
data/lib/semian/rails.rb CHANGED
@@ -4,6 +4,23 @@ require "active_record/connection_adapters/abstract_adapter"
4
4
 
5
5
  module Semian
6
6
  module Rails
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ # Translate ConnectionNotEstablished errors to their original
11
+ # cause if applicable. When we have a CircuitOpenErorr we don't
12
+ # want the Active Record error, but rather the original cause.
13
+ def new_client(config)
14
+ super
15
+ rescue ActiveRecord::ConnectionNotEstablished => e
16
+ if e.cause.is_a?(Mysql2::CircuitOpenError)
17
+ raise e.cause
18
+ else
19
+ raise
20
+ end
21
+ end
22
+ end
23
+
7
24
  def semian_resource
8
25
  @semian_resource ||= client_connection.semian_resource
9
26
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Semian
4
- VERSION = "0.14.0"
4
+ VERSION = "0.16.0"
5
5
  end
data/lib/semian.rb CHANGED
@@ -276,6 +276,11 @@ module Semian
276
276
  error_threshold: options[:error_threshold],
277
277
  error_threshold_timeout: options[:error_threshold_timeout],
278
278
  error_timeout: options[:error_timeout],
279
+ error_threshold_timeout_enabled: if options[:error_threshold_timeout_enabled].nil?
280
+ true
281
+ else
282
+ options[:error_threshold_timeout_enabled]
283
+ end,
279
284
  exceptions: Array(exceptions) + [::Semian::BaseError],
280
285
  half_open_resource_timeout: options[:half_open_resource_timeout],
281
286
  implementation: implementation(**options),
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.14.0
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Francis
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-09-07 00:00:00.000000000 Z
13
+ date: 2022-10-05 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: |2
16
16
  A Ruby C extention that is used to control access to shared resources