Skip to content

Commit

Permalink
Add Twitter::Error::RequestTimeout
Browse files Browse the repository at this point in the history
This is a new class to catch timeout errors, such that they may be
retried.

It may be used as follows:

begin
  # Make a request using a Twitter::REST::Client
rescue Twitter::Error::RequestTimeout
  retry
end

Prior to this patch, to get the same behavior, you'd need to do this:

begin
  # Make a request using a Twitter::REST::Client
rescue Timeout::Error, Twitter::Error => error
  if error.is_a?(Timeout::Error) || error.cause.is_a?(Timeout::Error) || error.cause.is_a?(Faraday::Error::TimeoutError)
    retry
  else
    raise
  end
end

See #401.
  • Loading branch information
sferik committed Jan 22, 2014
1 parent e83defc commit 3179537
Show file tree
Hide file tree
Showing 13 changed files with 44 additions and 18 deletions.
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,6 @@ CaseIndentation:

Lambda:
Enabled: false

RaiseArgs:
EnforcedStyle: compact
2 changes: 2 additions & 0 deletions etc/erd.dot
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ digraph classes {
Twitter__Error__InternalServerError [label="Twitter::Error::InternalServerError"]
Twitter__Error__NotAcceptable [label="Twitter::Error::NotAcceptable"]
Twitter__Error__NotFound [label="Twitter::Error::NotFound"]
Twitter__Error__RequestTimeout [label="Twitter::Error::RequestTimeout"]
Twitter__Error__ServiceUnavailable [label="Twitter::Error::ServiceUnavailable"]
Twitter__Error__TooManyRequests [label="Twitter::Error::TooManyRequests"]
Twitter__Error__Unauthorized [label="Twitter::Error::Unauthorized"]
Expand Down Expand Up @@ -111,6 +112,7 @@ digraph classes {
Twitter__Error__InternalServerError -> Twitter__Error
Twitter__Error__NotAcceptable -> Twitter__Error
Twitter__Error__NotFound -> Twitter__Error
Twitter__Error__RequestTimeout -> Twitter__Error
Twitter__Error__ServiceUnavailable -> Twitter__Error
Twitter__Error__TooManyRequests -> Twitter__Error
Twitter__Error__Unauthorized -> Twitter__Error
Expand Down
Binary file modified etc/erd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion lib/twitter/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def credentials?
def validate_credential_type!
credentials.each do |credential, value|
next if value.nil?
fail(Error::ConfigurationError, "Invalid #{credential} specified: #{value.inspect} must be a string or symbol.") unless value.is_a?(String) || value.is_a?(Symbol)
fail(Error::ConfigurationError.new("Invalid #{credential} specified: #{value.inspect} must be a string or symbol.")) unless value.is_a?(String) || value.is_a?(Symbol)
end
end

Expand Down
10 changes: 10 additions & 0 deletions lib/twitter/error/request_timeout.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require 'twitter/error'

module Twitter
class Error
# Raised when the Faraday connection times out
class RequestTimeout < Twitter::Error
HTTP_STATUS_CODE = 408
end
end
end
7 changes: 5 additions & 2 deletions lib/twitter/rest/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
require 'faraday'
require 'faraday/request/multipart'
require 'json'
require 'timeout'
require 'twitter/client'
require 'twitter/error'
require 'twitter/error/configuration_error'
require 'twitter/error/request_timeout'
require 'twitter/rest/api/direct_messages'
require 'twitter/rest/api/favorites'
require 'twitter/rest/api/friends_and_followers'
Expand Down Expand Up @@ -122,9 +124,10 @@ def request(method, path, params = {}, signature_params = params)
request.headers.update(request_headers(method, path, params, signature_params))
end
response.env
rescue Faraday::Error::TimeoutError, Timeout::Error => error
raise(Twitter::Error::RequestTimeout.new(error))
rescue Faraday::Error::ClientError, JSON::ParserError => error
error = Twitter::Error.new(error)
raise error
fail(Twitter::Error.new(error))
end

def request_headers(method, path, params = {}, signature_params = params)
Expand Down
2 changes: 1 addition & 1 deletion spec/twitter/error_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
stub_get('/1.1/statuses/user_timeline.json').with(:query => {:screen_name => 'sferik'}).to_return(:status => status, :body => body_message)
end
it "raises #{exception.name}" do
expect { @client.user_timeline('sferik') }.to raise_error exception
expect { @client.user_timeline('sferik') }.to raise_error(exception)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/twitter/geo_factory_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
expect(geo).to be_a Twitter::Geo::Polygon
end
it 'raises an IndexError when type is not specified' do
expect { Twitter::GeoFactory.new }.to raise_error IndexError
expect { Twitter::GeoFactory.new }.to raise_error(IndexError)
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/twitter/identifiable_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

describe '#initialize' do
it 'raises an IndexError when id is not specified' do
expect { Twitter::Identity.new }.to raise_error IndexError
expect { Twitter::Identity.new }.to raise_error(IndexError)
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/twitter/media_factory_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
expect(media).to be_a Twitter::Media::Photo
end
it 'raises an IndexError when type is not specified' do
expect { Twitter::MediaFactory.new }.to raise_error IndexError
expect { Twitter::MediaFactory.new }.to raise_error(IndexError)
end
end

Expand Down
4 changes: 2 additions & 2 deletions spec/twitter/rest/api/favorites_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,15 @@
stub_post('/1.1/favorites/create.json').with(:body => {:id => '25938088801'}).to_return(:status => 403, :headers => {:content_type => 'application/json; charset=utf-8'})
end
it 'raises a Forbidden error' do
expect { @client.favorite!(25_938_088_801) }.to raise_error Twitter::Error::Forbidden
expect { @client.favorite!(25_938_088_801) }.to raise_error(Twitter::Error::Forbidden)
end
end
context 'already favorited' do
before do
stub_post('/1.1/favorites/create.json').with(:body => {:id => '25938088801'}).to_return(:status => 403, :body => fixture('already_favorited.json'), :headers => {:content_type => 'application/json; charset=utf-8'})
end
it 'raises an AlreadyFavorited error' do
expect { @client.favorite!(25_938_088_801) }.to raise_error Twitter::Error::AlreadyFavorited
expect { @client.favorite!(25_938_088_801) }.to raise_error(Twitter::Error::AlreadyFavorited)
end
end
context 'with a URI object passed' do
Expand Down
8 changes: 4 additions & 4 deletions spec/twitter/rest/api/tweets_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@
stub_post('/1.1/statuses/update.json').to_return(:status => 403, :body => fixture('already_posted.json'), :headers => {:content_type => 'application/json; charset=utf-8'})
end
it 'raises an AlreadyPosted error' do
expect { @client.update("The problem with your code is that it's doing exactly what you told it to do.") }.to raise_error Twitter::Error::AlreadyPosted
expect { @client.update("The problem with your code is that it's doing exactly what you told it to do.") }.to raise_error(Twitter::Error::AlreadyPosted)
end
end
context 'with an in-reply-to status' do
Expand Down Expand Up @@ -333,15 +333,15 @@
stub_post('/1.1/statuses/retweet/25938088801.json').to_return(:status => 403, :headers => {:content_type => 'application/json; charset=utf-8'})
end
it 'raises a Forbidden error' do
expect { @client.retweet!(25_938_088_801) }.to raise_error Twitter::Error::Forbidden
expect { @client.retweet!(25_938_088_801) }.to raise_error(Twitter::Error::Forbidden)
end
end
context 'already retweeted' do
before do
stub_post('/1.1/statuses/retweet/25938088801.json').to_return(:status => 403, :body => fixture('already_retweeted.json'), :headers => {:content_type => 'application/json; charset=utf-8'})
end
it 'raises an AlreadyRetweeted error' do
expect { @client.retweet!(25_938_088_801) }.to raise_error Twitter::Error::AlreadyRetweeted
expect { @client.retweet!(25_938_088_801) }.to raise_error(Twitter::Error::AlreadyRetweeted)
end
end
context 'with a URI object passed' do
Expand Down Expand Up @@ -410,7 +410,7 @@
stub_post('/1.1/statuses/update_with_media.json').to_return(:status => 403, :body => fixture('already_posted.json'), :headers => {:content_type => 'application/json; charset=utf-8'})
end
it 'raises an AlreadyPosted error' do
expect { @client.update_with_media("The problem with your code is that it's doing exactly what you told it to do.", fixture('pbjt.gif')) }.to raise_error Twitter::Error::AlreadyPosted
expect { @client.update_with_media("The problem with your code is that it's doing exactly what you told it to do.", fixture('pbjt.gif')) }.to raise_error(Twitter::Error::AlreadyPosted)
end
end
end
Expand Down
18 changes: 13 additions & 5 deletions spec/twitter/rest/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,21 @@
@client.update_with_media('Update', fixture('pbjt.gif'))
expect(a_post('/1.1/statuses/update_with_media.json')).to have_been_made
end
it 'catches Faraday errors' do
allow(@client).to receive(:connection).and_raise(Faraday::Error::ClientError.new('Oops'))
expect { @client.send(:request, :get, '/path') }.to raise_error Twitter::Error
it 'catches and reraises Faraday timeout errors' do
allow(@client).to receive(:connection).and_raise(Faraday::Error::TimeoutError.new('execution expired'))
expect { @client.send(:request, :get, '/path') }.to raise_error(Twitter::Error::RequestTimeout)
end
it 'catches JSON::ParserError errors' do
it 'catches and reraises Timeout errors' do
allow(@client).to receive(:connection).and_raise(Timeout::Error.new('execution expired'))
expect { @client.send(:request, :get, '/path') }.to raise_error(Twitter::Error::RequestTimeout)
end
it 'catches and reraises Faraday client errors' do
allow(@client).to receive(:connection).and_raise(Faraday::Error::ClientError.new('connection failed'))
expect { @client.send(:request, :get, '/path') }.to raise_error(Twitter::Error)
end
it 'catches and reraises JSON::ParserError errors' do
allow(@client).to receive(:connection).and_raise(JSON::ParserError.new('unexpected token'))
expect { @client.send(:request, :get, '/path') }.to raise_error Twitter::Error
expect { @client.send(:request, :get, '/path') }.to raise_error(Twitter::Error)
end
end

Expand Down

0 comments on commit 3179537

Please sign in to comment.