active_job_exception_handler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 35ef233d0b45467e77ddedf1db4781f7afc49995
4
+ data.tar.gz: 0c1ebe0c56515afba4788383388b5875b4c9dfca
5
+ SHA512:
6
+ metadata.gz: 8b69f694263edf50d59ed2549d45d835fdb73a5d6d88c87ed4973f306157d57f76717af04353d8e51afba97e312b4e5321a5f58a0f881cef31dae2495ea89ce6
7
+ data.tar.gz: 827d1b59aa93ffda14c7ae64a7ebbbbad186ae73ce8c94e5fce9b3333002cb870d8fe7f39becda6283d92b52c98307f2fb85596aa3ae31ad7b09951e71449b2f
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2017 []().
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,149 @@
1
+ # ActiveJobExceptionHandler
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/active_job_exception_handler.svg)](http://badge.fury.io/rb/active_job_exception_handler)
4
+
5
+ <!-- Tocer[start]: Auto-generated, don't remove. -->
6
+
7
+ # Table of Contents
8
+
9
+ - [Features](#features)
10
+ - [Screencasts](#screencasts)
11
+ - [Requirements](#requirements)
12
+ - [Setup](#setup)
13
+ - [Usage](#usage)
14
+ - [Tests](#tests)
15
+ - [Versioning](#versioning)
16
+ - [Code of Conduct](#code-of-conduct)
17
+ - [Contributions](#contributions)
18
+ - [License](#license)
19
+ - [History](#history)
20
+ - [Credits](#credits)
21
+
22
+ <!-- Tocer[finish]: Auto-generated, don't remove. -->
23
+
24
+ # Features
25
+
26
+ # Screencasts
27
+
28
+ # Requirements
29
+
30
+ 0. [Ruby 2.4.1](https://www.ruby-lang.org)
31
+
32
+ # Setup
33
+
34
+ For a secure install, type the following (recommended):
35
+
36
+ gem cert --add <(curl --location --silent /gem-public.pem)
37
+ gem install active_job_exception_handler --trust-policy MediumSecurity
38
+
39
+ NOTE: A HighSecurity trust policy would be best but MediumSecurity enables signed gem verification
40
+ while allowing the installation of unsigned dependencies since they are beyond the scope of this
41
+ gem.
42
+
43
+ For an insecure install, type the following (not recommended):
44
+
45
+ gem install active_job_exception_handler
46
+
47
+ Add the following to your Gemfile:
48
+
49
+ gem "active_job_exception_handler"
50
+
51
+ # Usage
52
+
53
+ Initialize it like this:
54
+
55
+ ```ruby
56
+ class ApplicationJob < ActiveJob::Base
57
+
58
+ before_perform :initialize_exception_handler
59
+
60
+ def perform(normal:, credentials: {}, spawn_job_id:, exception_handler: default_exception_handler)
61
+ @exception_handler = exception_handler
62
+ initialize_exception_handling
63
+
64
+ exception_handler.process! do
65
+ return if skip?
66
+ collector.run run_options
67
+ emitter.flush!
68
+ kapost_client.update_credentials(adapter.updated_tokens) if adapter.refreshed_tokens?
69
+ perform_successful
70
+ end
71
+ end
72
+
73
+ protected
74
+
75
+ def exception_handler
76
+ @exception_handler ||= ExceptionHandler.new(exception_context: exception_context)
77
+ end
78
+
79
+ def exception_context
80
+ ExceptionContext.new(
81
+ source: self.class.name,
82
+ queue: queue_name,
83
+ args: arguments
84
+ )
85
+ end
86
+
87
+ def initialize_exception_handling
88
+ # implement this method to define how errors are handled
89
+ end
90
+ end
91
+ ```
92
+
93
+ And then use it in jobs like this:
94
+
95
+ ```ruby
96
+ class MyJob < ApplicationJob
97
+
98
+ def perform(...)
99
+ # ...
100
+ end
101
+
102
+ protected
103
+
104
+ def initialize_exception_handling
105
+ exception_handler.add HTTPServerError, :retryables # Transient HTTP error
106
+ exception_handler.add HTTPAuthenticationError, :unretryables # User credentials are wrong, don't retry
107
+ exception_handler.add HTTPNotFoundError, :ignorables # Page is gone, we don't care anymore
108
+ end
109
+
110
+ end
111
+ ```
112
+
113
+ # Tests
114
+
115
+ To test, run:
116
+
117
+ bundle exec rake
118
+
119
+ # Versioning
120
+
121
+ Read [Semantic Versioning](http://semver.org) for details. Briefly, it means:
122
+
123
+ - Major (X.y.z) - Incremented for any backwards incompatible public API changes.
124
+ - Minor (x.Y.z) - Incremented for new, backwards compatible, public API enhancements/fixes.
125
+ - Patch (x.y.Z) - Incremented for small, backwards compatible, bug fixes.
126
+
127
+ # Code of Conduct
128
+
129
+ Please note that this project is released with a [CODE OF CONDUCT](CODE_OF_CONDUCT.md). By
130
+ participating in this project you agree to abide by its terms.
131
+
132
+ # Contributions
133
+
134
+ Read [CONTRIBUTING](CONTRIBUTING.md) for details.
135
+
136
+ # License
137
+
138
+ Copyright (c) 2017 []().
139
+ Read [LICENSE](LICENSE.md) for details.
140
+
141
+ # History
142
+
143
+ Read [CHANGES](CHANGES.md) for details.
144
+ Built with [Gemsmith](https://github.com/bkuhlmann/gemsmith).
145
+
146
+ # Credits
147
+
148
+ Developed by [Paul Sadauskas]() and [Brooke Kuhlmann]() at
149
+ [Kapost](www.kapost.com).
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ExceptionHandler
4
+ RetryableError = Class.new(StandardError)
5
+
6
+ TYPES = %i[ignorables retryables unretryables].freeze
7
+
8
+ attr_reader(*TYPES)
9
+ attr_reader :error
10
+
11
+ def initialize(exception_context:,
12
+ rescue_retryable_errors:,
13
+ exception_processors: [ExceptionHandlerStatsdProcessor.new,
14
+ ExceptionHandlerActionableFaultProcessor.new],
15
+ logger: ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)))
16
+ @exception_context = exception_context
17
+ @exception_processors = exception_processors
18
+ @rescue_retryable_errors = rescue_retryable_errors
19
+ @logger = logger
20
+ @error = nil
21
+ @ignorables = []
22
+ @retryables = [Timeout::Error, Net::HTTPError, Errno::ECONNREFUSED]
23
+ @unretryables = []
24
+ end
25
+
26
+ def add(error, type)
27
+ fail(StandardError, "Invalid error category: #{type}.") unless TYPES.include?(type)
28
+ public_send(type) << error
29
+ end
30
+
31
+ def error?
32
+ error.present?
33
+ end
34
+
35
+ def process!
36
+ yield if block_given?
37
+
38
+ rescue *ignorables => error
39
+ handle_ignorable(error)
40
+
41
+ rescue *retryables => error
42
+ handle_retryable(error)
43
+
44
+ rescue *unretryables => error
45
+ handle_unretryable(error)
46
+
47
+ rescue StandardError => error
48
+ handle_unknown(error)
49
+ end
50
+
51
+ private
52
+
53
+ attr_reader :exception_context, :logger, :rescue_retryable_errors, :exception_processors
54
+
55
+ # Common actions that we want to perform for any type of error
56
+ def common_actions(error, type)
57
+ @error = error
58
+
59
+ log error, type
60
+
61
+ exception_processors.each do |processor|
62
+ processor.process(error, type, exception_context)
63
+ end
64
+ end
65
+
66
+ # Exceptions that we can't do anything about
67
+ def handle_ignorable(error)
68
+ common_actions(error, :ignorables)
69
+ end
70
+
71
+ # Transient exceptions that might go away upon a retry.
72
+ # Raise `ExceptionHandler::RetryableError` so shoryuken will pick up the
73
+ # job according to the retry intervals.
74
+ # Configure honeybadger to ignore this exception in the initializer.
75
+ #
76
+ # NOTE: Retries only apply to ApplicationJobs and
77
+ # don't have meaning for other objects like Collectors.
78
+ def handle_retryable(error)
79
+ common_actions(error, :retryables)
80
+
81
+ fail RetryableError unless rescue_retryable_errors
82
+ end
83
+
84
+ # Exceptions that we can't do anything about, but want to be notified on. This
85
+ # category should include errors where we might want to notify the customer, so
86
+ # they can take some action
87
+ def handle_unretryable(error)
88
+ common_actions(error, :unretryables)
89
+ end
90
+
91
+ # Unknown errors
92
+ # - Instrument and bubble out
93
+ def handle_unknown(error)
94
+ common_actions(error, :unknown)
95
+
96
+ fail error
97
+ end
98
+
99
+ def log(error, type)
100
+ return unless ENV["DUMP_EXCEPTIONS"]
101
+
102
+ logger.tagged self.class do |tagged_logger|
103
+ tagged_logger.info "Caught #{type} error: #{error.message}"
104
+ tagged_logger.info error.backtrace.join("\n")
105
+ end
106
+ end
107
+
108
+ class ExceptionContext
109
+ include Virtus.model
110
+ include ActiveModel::Validations
111
+
112
+ attribute :source, String
113
+ attribute :queue, String
114
+ attribute :args, Array
115
+
116
+ validates :source, :queue, :args, presence: true
117
+ end
118
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ActiveJobExceptionHandler
4
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveJobExceptionHandler
4
+ # Gem identity information.
5
+ module Identity
6
+ def self.name
7
+ "active_job_exception_handler"
8
+ end
9
+
10
+ def self.label
11
+ "ActiveJobExceptionHandler"
12
+ end
13
+
14
+ def self.version
15
+ "0.0.1"
16
+ end
17
+
18
+ def self.version_label
19
+ "#{label} #{version}"
20
+ end
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,177 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_job_exception_handler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Paul Sadauskas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '12.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '12.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: gemsmith
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '9.2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '9.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-state
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.5'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.5'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '4.7'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '4.7'
111
+ - !ruby/object:Gem::Dependency
112
+ name: reek
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '4.5'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '4.5'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.47'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.47'
139
+ description:
140
+ email:
141
+ - psadauskas@gmail.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files:
145
+ - README.md
146
+ - LICENSE.md
147
+ files:
148
+ - LICENSE.md
149
+ - README.md
150
+ - lib/active_job_exception_handler.rb
151
+ - lib/active_job_exception_handler/exception_context.rb
152
+ - lib/active_job_exception_handler/identity.rb
153
+ homepage: ''
154
+ licenses:
155
+ - MIT
156
+ metadata: {}
157
+ post_install_message:
158
+ rdoc_options: []
159
+ require_paths:
160
+ - lib
161
+ required_ruby_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "~>"
164
+ - !ruby/object:Gem::Version
165
+ version: '2.4'
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ requirements: []
172
+ rubyforge_project:
173
+ rubygems_version: 2.6.11
174
+ signing_key:
175
+ specification_version: 4
176
+ summary: ''
177
+ test_files: []