resque-exceptional 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.md +3 -0
- data/LICENSE +20 -0
- data/README.md +82 -0
- data/Rakefile +25 -0
- data/lib/resque/failure/exceptional.rb +159 -0
- data/lib/resque-exceptional.rb +8 -0
- data/test/exceptional_test.rb +118 -0
- data/test/resque_test.rb +10 -0
- data/test/test_helper.rb +60 -0
- metadata +150 -0
data/HISTORY.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Luke Antins
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
resque-exceptional
|
2
|
+
==================
|
3
|
+
|
4
|
+
resque-exceptional provides a Resque failure backend that sends exceptions
|
5
|
+
raised by jobs to http://getexceptional.com
|
6
|
+
|
7
|
+
Install & Quick Start
|
8
|
+
---------------------
|
9
|
+
|
10
|
+
Before you jump into code, you'll need a http://getexceptional.com account.
|
11
|
+
|
12
|
+
To install:
|
13
|
+
|
14
|
+
$ gem install resque-exceptional
|
15
|
+
|
16
|
+
### Example: Single Failure Backend
|
17
|
+
|
18
|
+
Using only the exceptional failure backend:
|
19
|
+
|
20
|
+
require 'resque'
|
21
|
+
require 'resque-exceptional'
|
22
|
+
|
23
|
+
Resque::Failure::Exceptional.configure do |config|
|
24
|
+
config.api_key = '505f2518c41866bb0be7ba434bb2b079'
|
25
|
+
config.use_ssl = false
|
26
|
+
end
|
27
|
+
|
28
|
+
Resque::Failure.backend = Resque::Failure::Exceptional
|
29
|
+
|
30
|
+
### Example: Multiple Failure Backends
|
31
|
+
|
32
|
+
Using both the redis and exceptional failure backends:
|
33
|
+
|
34
|
+
require 'resque'
|
35
|
+
require 'resque-exceptional'
|
36
|
+
|
37
|
+
require 'resque/failure/multiple'
|
38
|
+
require 'resque/failure/redis'
|
39
|
+
|
40
|
+
Resque::Failure::Exceptional.configure do |config|
|
41
|
+
config.api_key = '505f2518c41866bb0be7ba434bb2b079'
|
42
|
+
end
|
43
|
+
|
44
|
+
Resque::Failure::Multiple.classes = [Resque::Failure::Redis, Resque::Failure::Exceptional]
|
45
|
+
Resque::Failure.backend = Resque::Failure::Multiple
|
46
|
+
|
47
|
+
Configuration Options
|
48
|
+
---------------------
|
49
|
+
|
50
|
+
**Required**
|
51
|
+
|
52
|
+
* `api_key` - your getexceptional.com api key.
|
53
|
+
|
54
|
+
**HTTP Proxy Options** *(optional)*
|
55
|
+
|
56
|
+
* `proxy_host` - proxy server ip / hostname.
|
57
|
+
* `proxy_port` - proxy server port.
|
58
|
+
* `proxy_user` - proxy server username.
|
59
|
+
* `proxy_pass` - proxy server password.
|
60
|
+
|
61
|
+
**HTTP Client Options** *(optional)*
|
62
|
+
|
63
|
+
* `use_ssl` - set `true` if your plan supports ssl. (default: `false`)
|
64
|
+
* `http_open_timeout` - timeout in seconds to establish the connection. (default: `2`)
|
65
|
+
* `http_read_timeout` - timeout in seconds to wait for a reply. (default: `5`)
|
66
|
+
|
67
|
+
Note on Patches/Pull Requests
|
68
|
+
-----------------------------
|
69
|
+
|
70
|
+
* Fork the project.
|
71
|
+
* Make your feature addition or bug fix.
|
72
|
+
* Add tests for it. This is important so I don't break it in a future
|
73
|
+
version unintentionally.
|
74
|
+
* Commit, do not mess with the version. (if you want to have your own
|
75
|
+
version, that is fine but bump version in a commit by itself I can ignore
|
76
|
+
when I pull)
|
77
|
+
* Send me a pull request. Bonus points for topic branches.
|
78
|
+
|
79
|
+
Author
|
80
|
+
------
|
81
|
+
|
82
|
+
Luke Antins :: http://lividpenguin.com :: @lantins
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$LOAD_PATH.unshift 'lib'
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'yard'
|
6
|
+
require 'yard/rake/yardoc_task'
|
7
|
+
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
##
|
11
|
+
# Test task.
|
12
|
+
Rake::TestTask.new(:test) do |task|
|
13
|
+
task.test_files = FileList['test/*_test.rb']
|
14
|
+
task.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# docs task.
|
19
|
+
YARD::Rake::YardocTask.new :yardoc do |t|
|
20
|
+
t.files = ['lib/**/*.rb']
|
21
|
+
t.options = ['--output-dir', "doc/",
|
22
|
+
'--files', 'LICENSE HISTORY.md',
|
23
|
+
'--readme', 'README.md',
|
24
|
+
'--title', 'resque-exceptional documentation']
|
25
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module Resque
|
2
|
+
module Failure
|
3
|
+
|
4
|
+
# A resque failure backend that sends exception data to getexceptional.com
|
5
|
+
class Exceptional < Base
|
6
|
+
# Raised if the api_key is not set.
|
7
|
+
class APIKeyError < StandardError
|
8
|
+
end
|
9
|
+
|
10
|
+
# Our version number =)
|
11
|
+
Version = '0.0.1'
|
12
|
+
|
13
|
+
class << self
|
14
|
+
# API Settings.
|
15
|
+
attr_accessor :api_key
|
16
|
+
# HTTP Proxy Options.
|
17
|
+
attr_accessor :proxy_host, :proxy_port, :proxy_user, :proxy_pass
|
18
|
+
# HTTP Client Options.
|
19
|
+
attr_accessor :use_ssl, :http_open_timeout, :http_read_timeout
|
20
|
+
end
|
21
|
+
|
22
|
+
# Configures the failure backend. At a minimum you will need to set
|
23
|
+
# an api_key.
|
24
|
+
def self.configure
|
25
|
+
yield self
|
26
|
+
end
|
27
|
+
|
28
|
+
# Sends the exception data to the exceptional api.
|
29
|
+
#
|
30
|
+
# When a job fails, a new instance is created and #save is called.
|
31
|
+
def save
|
32
|
+
return unless response = http_post_request
|
33
|
+
|
34
|
+
if response.code == '200'
|
35
|
+
log "success - api accepted the exception data."
|
36
|
+
else
|
37
|
+
body = response.body if response.respond_to? :body
|
38
|
+
log "fail - expected: 200 OK, received: #{response.code} #{response.message}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Sends a HTTP Post to the exceptional api.
|
43
|
+
#
|
44
|
+
# @return [Net::HTTPResponse] http response data.
|
45
|
+
# @return [nil] if something went wrong.
|
46
|
+
def http_post_request
|
47
|
+
begin
|
48
|
+
return http_client.post(http_path_query, compressed_request, http_headers)
|
49
|
+
rescue APIKeyError
|
50
|
+
log 'error - you must set your api_key.'
|
51
|
+
rescue TimeoutError
|
52
|
+
log 'fail - timeout while contacting the api server.'
|
53
|
+
rescue Exception => e
|
54
|
+
log "fail - exception raised during http post. (#{e.class.name}: #{e.message})"
|
55
|
+
end
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
# HTTP headers to send.
|
60
|
+
#
|
61
|
+
# @return [Hash] http headers.
|
62
|
+
def http_headers
|
63
|
+
{ 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns the compressed request data.
|
67
|
+
def compressed_request
|
68
|
+
Zlib::Deflate.deflate(api_request.to_json, Zlib::BEST_SPEED)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Path & query options used by the HTTP Post.
|
72
|
+
#
|
73
|
+
# @raise [APIKeyError] if the api_key is not set.
|
74
|
+
# @return [String] http path & query options.
|
75
|
+
def http_path_query
|
76
|
+
raise APIKeyError, 'api key must be set.' unless self.class.api_key
|
77
|
+
hash_param = uniqueness_hash.nil? ? nil : "&hash=#{uniqueness_hash}"
|
78
|
+
"/api/errors?api_key=#{self.class.api_key}&protocol_version=5#{hash_param}"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Calculates a uniqueness md5sum of the exception backtrace if available.
|
82
|
+
#
|
83
|
+
# nb. this isn't documented in the public api... not sure if we should
|
84
|
+
# use it or not...
|
85
|
+
def uniqueness_hash
|
86
|
+
return nil if (exception.backtrace.nil? || exception.backtrace.empty?)
|
87
|
+
Digest::MD5.hexdigest(exception.backtrace.join)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Configures a HTTP client.
|
91
|
+
#
|
92
|
+
# @return [Net::HTTP] http client.
|
93
|
+
def http_client
|
94
|
+
# pass any proxy settings.
|
95
|
+
proxy = Net::HTTP::Proxy(self.class.proxy_host, self.class.proxy_port,
|
96
|
+
self.class.proxy_user, self.class.proxy_pass)
|
97
|
+
http = proxy.new('api.getexceptional.com', http_port)
|
98
|
+
|
99
|
+
# set http client options.
|
100
|
+
http.read_timeout = self.class.http_read_timeout || 5
|
101
|
+
http.open_timeout = self.class.http_open_timeout || 2
|
102
|
+
http.use_ssl = use_ssl?
|
103
|
+
|
104
|
+
http
|
105
|
+
end
|
106
|
+
|
107
|
+
# Helper method to return the correct HTTP port number.
|
108
|
+
def http_port
|
109
|
+
use_ssl? ? 443 : 80
|
110
|
+
end
|
111
|
+
|
112
|
+
# Helper method to check if were using SSL or not.
|
113
|
+
def use_ssl?
|
114
|
+
self.class.use_ssl || false
|
115
|
+
end
|
116
|
+
|
117
|
+
# Adds a prefix to log messages.
|
118
|
+
def log(msg)
|
119
|
+
super("resque-exception - #{msg}")
|
120
|
+
end
|
121
|
+
|
122
|
+
# API request data structure.
|
123
|
+
#
|
124
|
+
# @return [Hash] data structure expected by the api.
|
125
|
+
def api_request
|
126
|
+
{
|
127
|
+
'request' => {
|
128
|
+
'parameters' => {
|
129
|
+
'queue' => queue.to_s,
|
130
|
+
'job_class' => payload['class'].to_s,
|
131
|
+
'job_args' => payload['args'],
|
132
|
+
'worker' => worker.to_s
|
133
|
+
}
|
134
|
+
},
|
135
|
+
'application_environment' => {
|
136
|
+
'env' => ENV.to_hash,
|
137
|
+
'application_root_directory' => ENV['PWD']
|
138
|
+
},
|
139
|
+
'exception' => {
|
140
|
+
'occurred_at' => Time.now.iso8601,
|
141
|
+
'message' => "#{exception.class.name}: #{exception.message}",
|
142
|
+
'backtrace' => Array(exception.backtrace),
|
143
|
+
'exception_class' => exception.class.name
|
144
|
+
},
|
145
|
+
'rescue_block' => {
|
146
|
+
'name' => 'Resque Failure'
|
147
|
+
},
|
148
|
+
'client' => {
|
149
|
+
'name' => 'resque-exceptional',
|
150
|
+
'version' => Resque::Failure::Exceptional::Version,
|
151
|
+
'protocol_version' => 5
|
152
|
+
}
|
153
|
+
}
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
# Tests the failure backend works with resque, does not contact the api.
|
4
|
+
class ExceptionalTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@exception = TestApp.grab_exception
|
7
|
+
@worker = FakeWorker.new
|
8
|
+
@queue = 'test_queue'
|
9
|
+
@payload = { 'class' => 'TestJob', 'args' => ['foo', 'bar'] }
|
10
|
+
@failure = Resque::Failure::Exceptional.new(@exception, @worker, @queue, @payload)
|
11
|
+
end
|
12
|
+
|
13
|
+
# test we can build a hash to send to the api.
|
14
|
+
def test_can_build_api_request_data_hash
|
15
|
+
data = @failure.api_request
|
16
|
+
assert_kind_of Hash, data, 'should build a hash'
|
17
|
+
end
|
18
|
+
|
19
|
+
# include the minimum entries required by the api.
|
20
|
+
def test_api_request_includes_minimum_api_entries
|
21
|
+
data = @failure.api_request
|
22
|
+
|
23
|
+
assert_kind_of Hash, data['application_environment']
|
24
|
+
assert_kind_of Hash, data['application_environment']['env']
|
25
|
+
assert_kind_of String, data['application_environment']['application_root_directory']
|
26
|
+
|
27
|
+
assert_kind_of Hash, data['exception']
|
28
|
+
# test occurred_at that starts like: 2010-10-13T01:56:49
|
29
|
+
assert_match /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/, data['exception']['occurred_at']
|
30
|
+
assert_kind_of String, data['exception']['message']
|
31
|
+
assert_kind_of Array, data['exception']['backtrace']
|
32
|
+
assert_equal 'TestApp::Error', data['exception']['exception_class']
|
33
|
+
end
|
34
|
+
|
35
|
+
# include the resque information, we sneak it in as request data so we can
|
36
|
+
# view it via the web interface.
|
37
|
+
def test_api_request_includes_resque_info
|
38
|
+
data = @failure.api_request
|
39
|
+
|
40
|
+
assert_kind_of Hash, data['request']
|
41
|
+
assert_kind_of Hash, data['request']['parameters']
|
42
|
+
assert_kind_of String, data['request']['parameters']['queue']
|
43
|
+
assert_kind_of String, data['request']['parameters']['job_class']
|
44
|
+
assert_kind_of Array, data['request']['parameters']['job_args']
|
45
|
+
assert_kind_of String, data['request']['parameters']['worker']
|
46
|
+
end
|
47
|
+
|
48
|
+
# make it more obvious in the web interface this was a resque failure.
|
49
|
+
def test_api_request_includes_resque_block
|
50
|
+
data = @failure.api_request
|
51
|
+
|
52
|
+
assert_kind_of Hash, data['rescue_block']
|
53
|
+
assert_equal 'Resque Failure', data['rescue_block']['name']
|
54
|
+
end
|
55
|
+
|
56
|
+
# let them know who we are.
|
57
|
+
def test_api_request_includes_client_info
|
58
|
+
data = @failure.api_request
|
59
|
+
|
60
|
+
assert_equal 'resque-exceptional', data['client']['name'], 'should use the gem name'
|
61
|
+
assert_match /^\d+\.\d+\.\d+$/, data['client']['version'], 'should have a version number'
|
62
|
+
assert_kind_of Fixnum, data['client']['protocol_version']
|
63
|
+
end
|
64
|
+
|
65
|
+
# we need the ability to configure the failure backend before its created.
|
66
|
+
# config settings should be class variables.
|
67
|
+
def test_configure
|
68
|
+
Resque::Failure::Exceptional.configure do |config|
|
69
|
+
config.api_key = 'my api key.'
|
70
|
+
# everything below are http client options.
|
71
|
+
config.proxy_host = 'host.name.com'
|
72
|
+
config.proxy_port = 8080
|
73
|
+
config.proxy_user = 'foo'
|
74
|
+
config.proxy_pass = 'bar'
|
75
|
+
config.use_ssl = true
|
76
|
+
config.http_open_timeout = 5
|
77
|
+
config.http_read_timeout = 10
|
78
|
+
end
|
79
|
+
|
80
|
+
# reset everything to nil...
|
81
|
+
Resque::Failure::Exceptional.configure do |config|
|
82
|
+
options = %w{api_key proxy_host proxy_port proxy_user proxy_pass use_ssl
|
83
|
+
http_open_timeout http_read_timeout}
|
84
|
+
options.each { |opt| config.send("#{opt}=", nil) }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# failure backends need to define a save method.
|
89
|
+
def test_save_defined
|
90
|
+
assert_equal true, @failure.respond_to?(:save)
|
91
|
+
end
|
92
|
+
|
93
|
+
# we need a Net::HTTP client setup to send the data.
|
94
|
+
def test_http_client
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
# perform a test with the real api.
|
99
|
+
def test_live_fire
|
100
|
+
#omit 'comment this line, set your api key, test with real api!'
|
101
|
+
Resque::Failure::Exceptional.configure { |c| c.api_key = 'e6bee67c9a45ae41c8318e7d9a0e9d8d0dd9bc20' }
|
102
|
+
@failure.save
|
103
|
+
assert_match /^(resque-exception).*(success).*$/, @worker.log_history.first
|
104
|
+
# reset.
|
105
|
+
Resque::Failure::Exceptional.configure { |c| c.api_key = nil }
|
106
|
+
end
|
107
|
+
|
108
|
+
# we should fail if the api_key is not set.
|
109
|
+
def test_fail_if_api_key_nil
|
110
|
+
# should already be nil, but lets just be sure...
|
111
|
+
Resque::Failure::Exceptional.configure { |c| c.api_key = nil }
|
112
|
+
@failure.save
|
113
|
+
assert_match /^(resque-exception).*(error).*(api_key).*$/, @worker.log_history.first
|
114
|
+
end
|
115
|
+
|
116
|
+
# should handle exceptions raised during the HTTP Post.
|
117
|
+
# should return and not raise anything if we were successful.
|
118
|
+
end
|
data/test/resque_test.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
# make sure the worlds not fallen from beneith us.
|
4
|
+
class ResqueTest < Test::Unit::TestCase
|
5
|
+
def test_resque_version
|
6
|
+
major, minor, patch = Resque::Version.split('.')
|
7
|
+
assert_equal 1, major.to_i, 'major version does not match'
|
8
|
+
assert_operator minor.to_i, :>=, 8, 'minor version is too low'
|
9
|
+
end
|
10
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
dir = File.dirname(File.expand_path(__FILE__))
|
2
|
+
$LOAD_PATH.unshift dir + '/../lib'
|
3
|
+
$TESTING = true
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
require 'rubygems'
|
7
|
+
require 'simplecov'
|
8
|
+
require 'rr'
|
9
|
+
|
10
|
+
SimpleCov.start do
|
11
|
+
add_filter "/test/"
|
12
|
+
end
|
13
|
+
|
14
|
+
class Test::Unit::TestCase
|
15
|
+
include RR::Adapters::TestUnit
|
16
|
+
end
|
17
|
+
|
18
|
+
# require our failure backend to test.
|
19
|
+
require 'resque-exceptional'
|
20
|
+
|
21
|
+
# fake worker.
|
22
|
+
class FakeWorker
|
23
|
+
attr_reader :log_history
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@log_history = []
|
27
|
+
end
|
28
|
+
|
29
|
+
def log(msg)
|
30
|
+
@log_history << msg
|
31
|
+
p msg
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
'mr. fake resque worker.'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# test exceptions.
|
40
|
+
module TestApp
|
41
|
+
class Error < StandardError
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.method_bar
|
45
|
+
raise Error, 'example exception message. bar.'
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.method_foo
|
49
|
+
method_bar
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.grab_exception
|
53
|
+
begin
|
54
|
+
method_foo
|
55
|
+
rescue => e
|
56
|
+
return e
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: resque-exceptional
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Luke Antins
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-13 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: resque
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 55
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 8
|
33
|
+
- 0
|
34
|
+
version: 1.8.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: test-unit
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: rr
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 23
|
60
|
+
segments:
|
61
|
+
- 1
|
62
|
+
- 0
|
63
|
+
- 0
|
64
|
+
version: 1.0.0
|
65
|
+
type: :development
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: yard
|
69
|
+
prerelease: false
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
type: :development
|
80
|
+
version_requirements: *id004
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: simplecov
|
83
|
+
prerelease: false
|
84
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
hash: 19
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
- 3
|
93
|
+
- 0
|
94
|
+
version: 0.3.0
|
95
|
+
type: :development
|
96
|
+
version_requirements: *id005
|
97
|
+
description: " resque-exceptional provides a Resque failure backend that sends exceptions\n raised by jobs to getexceptional.com.\n"
|
98
|
+
email: luke@lividpenguin.com
|
99
|
+
executables: []
|
100
|
+
|
101
|
+
extensions: []
|
102
|
+
|
103
|
+
extra_rdoc_files: []
|
104
|
+
|
105
|
+
files:
|
106
|
+
- LICENSE
|
107
|
+
- Rakefile
|
108
|
+
- README.md
|
109
|
+
- HISTORY.md
|
110
|
+
- test/exceptional_test.rb
|
111
|
+
- test/resque_test.rb
|
112
|
+
- test/test_helper.rb
|
113
|
+
- lib/resque/failure/exceptional.rb
|
114
|
+
- lib/resque-exceptional.rb
|
115
|
+
has_rdoc: false
|
116
|
+
homepage: http://github.com/lantins/resque-exceptional
|
117
|
+
licenses: []
|
118
|
+
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
hash: 3
|
130
|
+
segments:
|
131
|
+
- 0
|
132
|
+
version: "0"
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
hash: 3
|
139
|
+
segments:
|
140
|
+
- 0
|
141
|
+
version: "0"
|
142
|
+
requirements: []
|
143
|
+
|
144
|
+
rubyforge_project:
|
145
|
+
rubygems_version: 1.3.7
|
146
|
+
signing_key:
|
147
|
+
specification_version: 3
|
148
|
+
summary: A Resque failure backend for getexceptional.com
|
149
|
+
test_files: []
|
150
|
+
|