resque-exceptional 0.0.1
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.
- 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
|
+
|