respawn 0.1.5 → 0.1.6

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: cde24c2f311c9468a6b9811fcc531c029b1d8addfee5e7a9b5c6283ca86e9cf3
4
- data.tar.gz: dab8ea8a99e90ef941cdce690fa2dad567351c289ad6d50a1bd7b65c325651b3
3
+ metadata.gz: 907c5b6836d134a5d5aad923a8a3998e471e853175f38eb03d8102f5ded7f75f
4
+ data.tar.gz: a36a96ac08c14eb76be898aaa47f9d45c05d7010acb787d9c02a37cb2fa2981e
5
5
  SHA512:
6
- metadata.gz: cee1d10a076206759a165f991bd1c8fec776e453a3525f55c44118b3939190da1acb87e949b7f6e6d4d36846281b5e6d1cbf6cb0194796adf58dd7e22d65bc06
7
- data.tar.gz: 54226cd2b318a05554bb1f7c8e9707894f50f5bf9587c19ef29389a4406864c68a786f85761ca0ba2436cc1938503a8d3eb9c5b23f044cacbdd705a99b2fb6b1
6
+ metadata.gz: bb18883bbbeb24d44c61d8a33b3e9d57141f668ca0fe9ec5c8f5ac718d920e65786579ecdf163f5ade8883a1f44f1b4b065c8e0e80068cbc2b49726e670a5b40
7
+ data.tar.gz: 449b7fc2bd2530194bf7c515df721186df79420121de956f37c9fad5f47bd4b91419899a6ee62fb7f1ff6347ab1f2eec80f54bdd4780e7be100bb39240ff5348
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Respawn
4
+ module ArrayTry
5
+ refine Array do
6
+ def try!(element)
7
+ include?(element) or
8
+ raise(
9
+ ArgumentError,
10
+ %(Element "#{element}" not found in array #{self}),
11
+ )
12
+
13
+ element
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module Respawn
2
+ class Enum
3
+ def initialize(values)
4
+ self.values = nvalues
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Respawn
4
+ ENVIRONMENTS = %w[
5
+ development
6
+ production
7
+ test
8
+ ].freeze
9
+
10
+ Environment = Data.define(:env) do
11
+ using ArrayTry
12
+
13
+ def initialize(env:)
14
+ ENVIRONMENTS.try!(env)
15
+
16
+ super
17
+ end
18
+
19
+ ENVIRONMENTS.each do |name|
20
+ define_method("#{name}?") do
21
+ env == name
22
+ end
23
+ end
24
+
25
+ def self.default
26
+ new(
27
+ ENV.fetch("RUBY_ENV") do
28
+ ENV.fetch("RAILS_ENV", "production")
29
+ end,
30
+ )
31
+ end
32
+ end
33
+ end
@@ -2,14 +2,11 @@
2
2
 
3
3
  module Respawn
4
4
  class ExceptionDetector
5
- PREDEFINED_EXCEPTIONS = [
6
- EOFError,
7
- Errno::ECONNABORTED,
8
- Errno::ECONNRESET,
9
- Errno::EHOSTUNREACH,
10
- ].freeze
11
-
12
- DYNAMIC_EXCEPTIONS = [
5
+ EXCEPTIONS = [
6
+ "EOFError",
7
+ "Errno::ECONNABORTED",
8
+ "Errno::ECONNRESET",
9
+ "Errno::EHOSTUNREACH",
13
10
  "SocketError",
14
11
  "Faraday::ConnectionFailed",
15
12
  "Faraday::TimeoutError",
@@ -19,18 +16,19 @@ module Respawn
19
16
  "Net::ReadTimeout",
20
17
  "OpenSSL::SSL::SSLError",
21
18
  "OpenURI::HTTPError",
19
+ "TestException",
22
20
  ].freeze
23
21
 
24
- def self.call(...)
25
- new(...).call
22
+ def self.call(env: Environment.default)
23
+ if env.test?
24
+ new.call
25
+ else
26
+ @_call ||= new.call
27
+ end
26
28
  end
27
29
 
28
30
  def call
29
- PREDEFINED_EXCEPTIONS + dynamic_exceptions
30
- end
31
-
32
- def dynamic_exceptions
33
- DYNAMIC_EXCEPTIONS.filter_map do
31
+ EXCEPTIONS.filter_map do
34
32
  Object.const_get(it) if Object.const_defined?(it)
35
33
  end
36
34
  end
@@ -14,7 +14,7 @@ module Respawn
14
14
  return if self.block
15
15
 
16
16
  if onfail != :handler
17
- raise Try::Error, "Cannot define a block unless onfail is :handler"
17
+ raise Error, "Cannot define a block unless onfail is :handler"
18
18
  end
19
19
 
20
20
  self.block = block
@@ -2,8 +2,17 @@
2
2
 
3
3
  module Respawn
4
4
  class NotifierDetector
5
- def self.call(...)
6
- new(...).call
5
+ # Postpone the actual setup until the first use of the method, to make
6
+ # sure that all the dependencies are loaded and all constants are already
7
+ # available. Memoize the result of first run, to avoid processing all the
8
+ # logic in subsequent invocations.
9
+
10
+ def self.call(env: Environment.default)
11
+ if env.test?
12
+ new.call
13
+ else
14
+ @_call ||= new.call
15
+ end
7
16
  end
8
17
 
9
18
  def call
@@ -12,8 +21,10 @@ module Respawn
12
21
 
13
22
  private
14
23
 
24
+ attr_accessor :notifier
25
+
15
26
  def detect_notifier
16
- if defined?(TestNotifier)
27
+ if defined?(::TestNotifier)
17
28
  TestNotifier.method(:call)
18
29
  elsif defined?(::Sentry)
19
30
  Sentry.method(:capture_exception)
@@ -24,7 +35,12 @@ module Respawn
24
35
  elsif defined?(::Rollbar)
25
36
  :rollbar
26
37
  else
27
- proc {}
38
+ proc do
39
+ raise(
40
+ Error,
41
+ "Notifier called, but no notifier detected!",
42
+ )
43
+ end
28
44
  end
29
45
  end
30
46
  end
data/lib/respawn/setup.rb CHANGED
@@ -1,10 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Respawn
4
+ ONFAIL = [
5
+ :notify,
6
+ :nothing,
7
+ :raise,
8
+ :handler,
9
+ ].freeze
10
+
11
+ OPTIONS = {
12
+ notifier: NotifierDetector,
13
+ ex: ExceptionDetector,
14
+ onfail: :raise,
15
+ predicate: [],
16
+ tries: 5,
17
+ wait: 0.5,
18
+ env: -> { Environment.default },
19
+ setup: nil,
20
+ }.freeze
21
+
4
22
  Setup =
5
- Data.define(
6
- :notifier,
7
- :cause,
8
- :predicate,
9
- )
23
+ Data.define(*OPTIONS.keys) do
24
+ def initialize(**options)
25
+ with_defaults =
26
+ OPTIONS.map.to_h do |key, value|
27
+ [
28
+ key,
29
+ options.fetch(key) do
30
+ if value.respond_to?(:call)
31
+ value.call
32
+ else
33
+ value
34
+ end
35
+ end
36
+ ]
37
+ end
38
+
39
+ super(with_defaults)
40
+ end
41
+ end
10
42
  end
data/lib/respawn/try.rb CHANGED
@@ -1,43 +1,33 @@
1
1
  module Respawn
2
- Environment = Data.define(:env) do
3
- def test? = env == "test"
4
- end
5
-
6
2
  class Try
7
- class Error < StandardError; end
8
-
9
- ONFAIL = [
10
- :notify,
11
- :nothing,
12
- :raise,
13
- :handler,
14
- ].freeze
3
+ using ArrayTry
15
4
 
16
5
  def self.call(*, **, &)
17
6
  new(*, **).call(&)
18
7
  end
19
8
 
20
- def initialize(*exceptions, predicate: [], tries: 5, onfail: :notify, wait: 0.5, env: nil)
21
- self.predicate = predicate
9
+ def initialize(*exceptions, **options)
10
+ options.keys.each { OPTIONS.keys.try!(it) }
11
+
12
+ self.setup = options.fetch(:setup, Setup.new(**options))
13
+
14
+ self.notifier = options.fetch(:notifier, setup.notifier)
15
+ self.predicate = options.fetch(:predicate, setup.predicate)
16
+
17
+ exceptions = setup.ex if exceptions.empty?
18
+
22
19
  self.exceptions = parse_exceptions(exceptions) + [PredicateError]
23
- self.tries = tries
24
- self.onfail = ONFAIL.zip(ONFAIL).to_h.fetch(onfail)
25
- self.wait = wait
20
+ self.tries = options.fetch(:tries, setup.tries)
21
+ self.onfail = ONFAIL.try! options.fetch(:onfail, setup.onfail)
22
+ self.wait = options.fetch(:wait, setup.wait)
23
+ self.env = options.fetch(:env, Environment.default)
24
+
26
25
  self.handler = Handler.new(onfail)
27
- self.env = env || Environment.new(default_environment)
28
26
  end
29
27
 
30
28
  def call
31
- yield(handler).tap do |result|
32
- Array(predicate).each.with_index do |condition, index|
33
- if condition.call(result)
34
- raise(
35
- PredicateError,
36
- "Predicate ##{index} matched (#{condition.inspect})",
37
- )
38
- end
39
- end
40
- end
29
+ yield(handler)
30
+ .tap(&method(:check_predicates))
41
31
  rescue *exceptions => e
42
32
  self.tries = tries - 1
43
33
  handler.retry_number += 1
@@ -52,12 +42,25 @@ module Respawn
52
42
 
53
43
  private
54
44
 
55
- attr_accessor :exceptions, :tries, :onfail, :wait, :handler, :env, :predicate
45
+ attr_accessor(
46
+ :exceptions,
47
+ :tries,
48
+ :onfail,
49
+ :wait,
50
+ :handler,
51
+ :env,
52
+ :predicate,
53
+ :setup,
54
+ :notifier,
55
+ )
56
56
 
57
- def default_environment
58
- ENV.fetch("RUBY_ENV") do
59
- ENV.fetch("RAILS_ENV") do
60
- "production"
57
+ def check_predicates(result)
58
+ Array(predicate).each.with_index do |condition, index|
59
+ if condition.call(result)
60
+ raise(
61
+ PredicateError,
62
+ "Predicate ##{index} matched (#{condition.inspect})",
63
+ )
61
64
  end
62
65
  end
63
66
  end
@@ -65,7 +68,7 @@ module Respawn
65
68
  def perform_fail(exception)
66
69
  case onfail
67
70
  in :notify
68
- Respawn.default_setup.notifier.call(exception)
71
+ notifier.call(exception)
69
72
  in :nothing
70
73
  nil
71
74
  in :raise
@@ -76,16 +79,11 @@ module Respawn
76
79
  end
77
80
 
78
81
  def parse_exceptions(list)
79
- list.flat_map do |exception|
80
- if exception == :network_errors
81
- Respawn.default_setup.cause
82
-
82
+ list.each do |exception|
83
83
  # This comparision will raise an error if the exception is not
84
84
  # a class, which is what we want.
85
85
 
86
- elsif exception <= Exception
87
- exception
88
- end
86
+ raise Error, "Invalid exception passsed" unless exception <= Exception
89
87
  end
90
88
  end
91
89
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Respawn
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.6"
5
5
  end
data/lib/respawn.rb CHANGED
@@ -2,10 +2,6 @@
2
2
 
3
3
  require "zeitwerk"
4
4
 
5
- loader = Zeitwerk::Loader.for_gem
6
- loader.setup
7
- loader.eager_load
8
-
9
5
  module Respawn
10
6
  class Error < StandardError; end
11
7
  class PredicateError < StandardError; end
@@ -13,17 +9,8 @@ module Respawn
13
9
  def self.try(...)
14
10
  Try.call(...)
15
11
  end
16
-
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
12
  end
13
+
14
+ loader = Zeitwerk::Loader.for_gem
15
+ loader.setup
16
+ loader.eager_load
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.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mariusz Drozdziel
@@ -58,6 +58,9 @@ extensions: []
58
58
  extra_rdoc_files: []
59
59
  files:
60
60
  - lib/respawn.rb
61
+ - lib/respawn/array_try.rb
62
+ - lib/respawn/enum.rb
63
+ - lib/respawn/environment.rb
61
64
  - lib/respawn/exception_detector.rb
62
65
  - lib/respawn/handler.rb
63
66
  - lib/respawn/notifier_detector.rb