respawn 0.1.3 → 0.1.4

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
  SHA256:
3
- metadata.gz: 6d12952077bf536b30a67272ea992ebd5771ce9e265efde7c0b02587b8f59178
4
- data.tar.gz: 18a6f35a14f93916cefb09ca6d94e41b3aa54e87d5deae0600c12f9d350ce087
3
+ metadata.gz: b9ce4db696ee967e602013fa85f37caf81b7bff5afa2fb7af1b12c6ba548a336
4
+ data.tar.gz: 9461debe887911b3256159d94fe156d89e1c0c10e80f3e30f2fbbef18bb7ddb3
5
5
  SHA512:
6
- metadata.gz: 65526d3bc42433e41091b96e624f3e4ef0459f97d90a314dac3173facbc9aaec977bf61a6513a2c47efd1ee77943ec81a1078fe05ff160cef90cc0f6f94a5dc8
7
- data.tar.gz: 2b68c30c68067006925c45250d27d42ed1acd5eae1565d398055ade4804a8a4aece5b2d00ec946adad3649361157d8de6245b95867366c55936ad86c6c0760c9
6
+ metadata.gz: c11d9f8166b63a5e2f73f856b8fbff47104159e9ef2be89ca9914d5bf5ea8a52d85a996f49ed9016082ac35074970aa7427b9dd399ea755090fcb39d9d817810
7
+ data.tar.gz: 2c5264cfe13032166e06e4c6d6f009399f487b44c27dfa6766e66e231a958f7007c0bb685bafb42ae47309ce93d053d179d4e0a0509f55d74b3b8d4ceb99426e
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Respawn
4
+ class ExceptionDetector
5
+ PREDEFINED_EXCEPTIONS = [
6
+ EOFError,
7
+ Errno::ECONNABORTED,
8
+ Errno::ECONNRESET,
9
+ Errno::EHOSTUNREACH,
10
+ ].freeze
11
+
12
+ DYNAMIC_EXCEPTIONS = [
13
+ "SocketError",
14
+ "Faraday::ConnectionFailed",
15
+ "Faraday::TimeoutError",
16
+ "Faraday::ClientError",
17
+ "Faraday::ServerError",
18
+ "Net::OpenTimeout",
19
+ "Net::ReadTimeout",
20
+ "OpenSSL::SSL::SSLError",
21
+ "OpenURI::HTTPError",
22
+ ].freeze
23
+
24
+ def self.call(...)
25
+ new(...).call
26
+ end
27
+
28
+ def call
29
+ PREDEFINED_EXCEPTIONS + dynamic_exceptions
30
+ end
31
+
32
+ def dynamic_exceptions
33
+ DYNAMIC_EXCEPTIONS.filter_map do
34
+ Object.const_get(it) if Object.const_defined?(it)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,32 @@
1
+ module Respawn
2
+ class Handler
3
+ def initialize(onfail)
4
+ self.onfail = onfail
5
+ self.retry_number = 0
6
+ # self.predicates = []
7
+ end
8
+
9
+ # def predicate(&block)
10
+ # self.predicates << block
11
+ # end
12
+
13
+ def define(&block)
14
+ return if self.block
15
+
16
+ if onfail != :handler
17
+ raise Try::Error, "Cannot define a block unless onfail is :handler"
18
+ end
19
+
20
+ self.block = block
21
+ end
22
+
23
+ attr_accessor :onfail, :retry_number
24
+
25
+ attr_reader :block
26
+
27
+ private
28
+
29
+ attr_accessor :onfail, :predicates
30
+ attr_writer :block
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Respawn
4
+ class NotifierDetector
5
+ def self.call(...)
6
+ new(...).call
7
+ end
8
+
9
+ def call
10
+ detect_notifier
11
+ end
12
+
13
+ private
14
+
15
+ def detect_notifier
16
+ if defined?(TestNotifier)
17
+ TestNotifier.method(:call)
18
+ elsif defined?(::Sentry)
19
+ Sentry.method(:capture_exception)
20
+ elsif defined?(::Airbrake)
21
+ :airbrake
22
+ elsif defined?(::Bugsnag)
23
+ :bugsnag
24
+ elsif defined?(::Rollbar)
25
+ :rollbar
26
+ else
27
+ proc {}
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,4 @@
1
+ module Respawn
2
+ class Predicate
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Respawn
4
+ Setup =
5
+ Data.define(
6
+ :notifier,
7
+ :cause,
8
+ :predicate,
9
+ )
10
+ end
data/lib/respawn/try.rb CHANGED
@@ -6,22 +6,6 @@ module Respawn
6
6
  class Try
7
7
  class Error < StandardError; end
8
8
 
9
- COMMON_NETWORK_EXCEPTIONS = [
10
- EOFError,
11
- defined?(SocketError) && SocketError,
12
- Errno::ECONNABORTED,
13
- Errno::ECONNRESET,
14
- Errno::EHOSTUNREACH,
15
- # Faraday::ConnectionFailed,
16
- # Faraday::TimeoutError,
17
- # Faraday::ClientError,
18
- # Faraday::ServerError,
19
- # Net::OpenTimeout,
20
- # Net::ReadTimeout,
21
- # OpenSSL::SSL::SSLError,
22
- # OpenURI::HTTPError,
23
- ].compact.freeze
24
-
25
9
  ONFAIL = [
26
10
  :notify,
27
11
  :nothing,
@@ -29,37 +13,31 @@ module Respawn
29
13
  :handler,
30
14
  ].freeze
31
15
 
32
- class Handler
33
- attr_accessor :block
34
-
35
- def define(&block)
36
- self.block = block
37
- end
38
- end
39
-
40
- class NullHandler
41
- def define(&)
42
- raise Error, "Cannot define a block unless onfail is :handler"
43
- end
44
- end
45
-
46
16
  def self.call(*, **, &)
47
17
  new(*, **).call(&)
48
18
  end
49
19
 
50
- def initialize(*exceptions, tries: 5, onfail: :notify, wait: 0.5, env: nil)
51
- self.exceptions = parse_exceptions(exceptions)
20
+ def initialize(*exceptions, predicate: [], tries: 5, onfail: :notify, wait: 0.5, env: nil)
21
+ self.predicate = predicate
22
+ self.exceptions = parse_exceptions(exceptions) + [PredicateError]
52
23
  self.tries = tries
53
24
  self.onfail = ONFAIL.zip(ONFAIL).to_h.fetch(onfail)
54
25
  self.wait = wait
55
- self.handler = handler_for(onfail)
26
+ self.handler = Handler.new(onfail)
56
27
  self.env = env || Environment.new(default_environment)
57
28
  end
58
29
 
59
30
  def call
60
- yield(handler)
31
+ yield(handler).tap do |result|
32
+ Array(predicate).each.with_index do |condition, index|
33
+ if condition.call(result)
34
+ raise PredicateError, "Predicate #{condition.inspect} matched the result"
35
+ end
36
+ end
37
+ end
61
38
  rescue *exceptions => e
62
39
  self.tries = tries - 1
40
+ handler.retry_number += 1
63
41
 
64
42
  if tries.positive?
65
43
  Kernel.sleep(wait) unless env.test?
@@ -71,7 +49,7 @@ module Respawn
71
49
 
72
50
  private
73
51
 
74
- attr_accessor :exceptions, :tries, :onfail, :wait, :handler, :env
52
+ attr_accessor :exceptions, :tries, :onfail, :wait, :handler, :env, :predicate
75
53
 
76
54
  def default_environment
77
55
  ENV.fetch("RUBY_ENV") do
@@ -81,18 +59,10 @@ module Respawn
81
59
  end
82
60
  end
83
61
 
84
- def handler_for(onfail)
85
- if onfail == :handler
86
- Handler.new
87
- else
88
- NullHandler.new
89
- end
90
- end
91
-
92
62
  def perform_fail(exception)
93
63
  case onfail
94
64
  in :notify
95
- # Sentry.capture_exception(exception)
65
+ Respawn.default_setup.notifier.call(exception)
96
66
  in :nothing
97
67
  nil
98
68
  in :raise
@@ -105,7 +75,7 @@ module Respawn
105
75
  def parse_exceptions(list)
106
76
  list.flat_map do |exception|
107
77
  if exception == :network_errors
108
- COMMON_NETWORK_EXCEPTIONS
78
+ Respawn.default_setup.cause
109
79
 
110
80
  # This comparision will raise an error if the exception is not
111
81
  # a class, which is what we want.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Respawn
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.4"
5
5
  end
data/lib/respawn.rb CHANGED
@@ -2,14 +2,28 @@
2
2
 
3
3
  require "zeitwerk"
4
4
 
5
+ loader = Zeitwerk::Loader.for_gem
6
+ loader.setup
7
+ loader.eager_load
8
+
5
9
  module Respawn
6
10
  class Error < StandardError; end
11
+ class PredicateError < StandardError; end
7
12
 
8
13
  def self.try(...)
9
14
  Try.call(...)
10
15
  end
11
- end
12
16
 
13
- loader = Zeitwerk::Loader.for_gem
14
- loader.setup
15
- loader.eager_load
17
+ # Postpone the actuall setup until the first use of the method, to make
18
+ # sure that all the dependencies are loaded and all constants are already
19
+ # available.
20
+
21
+ def self.default_setup
22
+ @_default_setup ||=
23
+ Setup.new(
24
+ notifier: NotifierDetector.call,
25
+ cause: ExceptionDetector.call,
26
+ predicate: [],
27
+ )
28
+ end
29
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: respawn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mariusz Drozdziel
@@ -9,6 +9,20 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: pry
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.15'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.15'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: rspec
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -44,6 +58,11 @@ extensions: []
44
58
  extra_rdoc_files: []
45
59
  files:
46
60
  - lib/respawn.rb
61
+ - lib/respawn/exception_detector.rb
62
+ - lib/respawn/handler.rb
63
+ - lib/respawn/notifier_detector.rb
64
+ - lib/respawn/predicate.rb
65
+ - lib/respawn/setup.rb
47
66
  - lib/respawn/try.rb
48
67
  - lib/respawn/version.rb
49
68
  homepage: https://github.com/marzdrel/respawn