New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

thread safe? #354

Closed
veesahni opened this Issue Feb 22, 2013 · 18 comments

Comments

Projects
None yet
9 participants
@veesahni

veesahni commented Feb 22, 2013

I'm using the twitter gem within sidekiq to issue a number or parallel requests to twitter and see intermittent client errors. Although I get around this by retrying, I'm trying to better understand what's going on

Twitter::Error::ClientError - end of file reached:
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/openssl/buffering.rb:174:in `sysread_nonblock'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/openssl/buffering.rb:174:in `read_nonblock'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/protocol.rb:141:in `rbuf_fill'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/protocol.rb:122:in `readuntil'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/protocol.rb:132:in `readline'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:2770:in `read_chunked'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:2750:in `read_body_0'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:2710:in `read_body'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1029:in `block in get'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1322:in `block (2 levels) in transport_request'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:2671:in `reading_body'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1321:in `block in transport_request'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1316:in `catch'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1316:in `transport_request'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1293:in `request'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/rest-client-1.6.7/lib/restclient/net_http_ext.rb:51:in `request'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1286:in `block in request'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:745:in `start'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1284:in `request'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/rest-client-1.6.7/lib/restclient/net_http_ext.rb:51:in `request'
  /home/something/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1026:in `get'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/faraday-0.8.5/lib/faraday/adapter/net_http.rb:73:in `perform_request'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/faraday-0.8.5/lib/faraday/adapter/net_http.rb:38:in `call'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/faraday-0.8.5/lib/faraday/response.rb:8:in `call'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/faraday-0.8.5/lib/faraday/response.rb:8:in `call'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/faraday-0.8.5/lib/faraday/response.rb:8:in `call'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/faraday-0.8.5/lib/faraday/request/url_encoded.rb:14:in `call'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/faraday-0.8.5/lib/faraday/request/multipart.rb:13:in `call'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/twitter-4.5.0/lib/twitter/request/multipart_with_file.rb:14:in `call'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/faraday-0.8.5/lib/faraday/connection.rb:245:in `run_request'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/faraday-0.8.5/lib/faraday/connection.rb:98:in `get'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/twitter-4.5.0/lib/twitter/client.rb:81:in `request'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/twitter-4.5.0/lib/twitter/client.rb:64:in `get'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/twitter-4.5.0/lib/twitter/api/utils.rb:82:in `object_from_response'
  /home/something/.rvm/gems/ruby-1.9.3-p194/gems/twitter-4.5.0/lib/twitter/api/search.rb:32:in `search'

There have been some discussions on multi threaded problems with Faraday:
lostisland/faraday#181
lostisland/faraday#204

The referenced pull request is not included in the latest 0.8.5 release of Faraday.

So, I'm wondering if the twitter module is thread safe for usage in sidekiq?

/cc @mperham

@sferik

This comment has been minimized.

Owner

sferik commented Feb 26, 2013

I'm somewhat skeptical that:

  1. this is a threading error and
  2. it's being caused by code in the twitter gem.

To me, it looks like the error is occurring in openssl, net/http, or faraday. To further debug this problem, I suggest you try to reproduce the problem under the following configurations:

  1. Disable HTTPS. This should tell us whether the problem is in openssl. This can be accomplished by setting a custom endpoint for your client.

    Twitter.endpoint = "http://api.twitter.com"
    # or
    client = Twitter::Client.new(:endpoint => "http://api.twitter.com")
  2. Change the default HTTP adapter. This will tell us whether the problem is in net/http. This can be accomplished by setting a custom middleware stack:

    middleware = Proc.new do |builder|
      builder.use Twitter::Request::MultipartWithFile
      builder.use Faraday::Request::Multipart
      builder.use Faraday::Request::UrlEncoded
      builder.use Twitter::Response::RaiseError, Twitter::Error::ClientError
      builder.use Twitter::Response::ParseJson
      builder.use Twitter::Response::RaiseError, Twitter::Error::ServerError
      builder.adapter :typhoeus
    end
    
    Twitter.middleware = Faraday::Builder.new(&middleware)
    # or
    client = Twitter::Client.new(:middleware => Faraday::Builder.new(&middleware))
  3. Use faraday 0.9.0.pre. This will test whether the problem is in faraday. This can be accomplished by pointing to faraday's Git source in your Gemfile:

    gem 'faraday', '0.9.0.pre', :git => 'git://github.com/lostisland/faraday.git'

    Then bundle.

If you receive the same error in both of these configurations, that would be surprising to me. If you receive different errors in these configurations, that would shed more light on the nature of this issue.

Thanks!

@veesahni

This comment has been minimized.

veesahni commented Mar 1, 2013

Thanks Erik - I'll give these options a try and see if I can narrow it down further

@joekain

This comment has been minimized.

joekain commented Mar 9, 2013

I've seen the same problem with a single threaded app. I'm using:

ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.4.0]

I tried suggestions 1 and 3 but the problem still reproduced. Suggestion 2 failed differently:

/Users/jkain/.rvm/gems/ruby-1.9.3-p0/bundler/gems/faraday-36379e01afa5/lib/faraday/middleware.rb:20:in `new': missing dependency for Faraday::Adapter::Typhoeus: cannot load such file -- typhoeus (RuntimeError)
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/bundler/gems/faraday-36379e01afa5/lib/faraday/rack_builder.rb:44:in `build'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/bundler/gems/faraday-36379e01afa5/lib/faraday/rack_builder.rb:158:in `block in to_app'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/bundler/gems/faraday-36379e01afa5/lib/faraday/rack_builder.rb:158:in `each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/bundler/gems/faraday-36379e01afa5/lib/faraday/rack_builder.rb:158:in `inject'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/bundler/gems/faraday-36379e01afa5/lib/faraday/rack_builder.rb:158:in `to_app'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/bundler/gems/faraday-36379e01afa5/lib/faraday/rack_builder.rb:152:in `app'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/bundler/gems/faraday-36379e01afa5/lib/faraday/rack_builder.rb:135:in `build_response'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/bundler/gems/faraday-36379e01afa5/lib/faraday/connection.rb:351:in `run_request'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/bundler/gems/faraday-36379e01afa5/lib/faraday/connection.rb:133:in `get'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/twitter-4.5.0/lib/twitter/client.rb:81:in `request'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/twitter-4.5.0/lib/twitter/client.rb:64:in `get'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/twitter-4.5.0/lib/twitter/api/utils.rb:82:in `object_from_response'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/twitter-4.5.0/lib/twitter/api/search.rb:32:in `search'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/twitter-4.5.0/lib/Twitter.rb:52:in `method_missing'
    from ./stage_user.rb:31:in `fetch_tweets_for_user'
    from ./stage_user.rb:51:in `block (2 levels) in <main>'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/mongoid-3.0.23/lib/mongoid/contextual/mongo.rb:577:in `yield_document'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/mongoid-3.0.23/lib/mongoid/contextual/mongo.rb:133:in `block (2 levels) in each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/moped-1.4.3/lib/moped/query.rb:77:in `block in each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/moped-1.4.3/lib/moped/cursor.rb:26:in `block in each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/moped-1.4.3/lib/moped/cursor.rb:26:in `each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/moped-1.4.3/lib/moped/cursor.rb:26:in `each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/moped-1.4.3/lib/moped/query.rb:76:in `each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/moped-1.4.3/lib/moped/query.rb:76:in `each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/mongoid-3.0.23/lib/mongoid/contextual/mongo.rb:132:in `block in each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/mongoid-3.0.23/lib/mongoid/contextual/mongo.rb:556:in `selecting'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/mongoid-3.0.23/lib/mongoid/contextual/mongo.rb:131:in `each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/mongoid-3.0.23/lib/mongoid/contextual.rb:18:in `each'
    from /Users/jkain/.rvm/gems/ruby-1.9.3-p0/gems/mongoid-3.0.23/lib/mongoid/finders.rb:14:in `each'
    from ./stage_user.rb:50:in `block in <main>'
    from ./stage_user.rb:46:in `loop'
    from ./stage_user.rb:46:in `<main>'
@sferik

This comment has been minimized.

Owner

sferik commented Mar 9, 2013

@joekain to get 2 working, you need to add gem 'typhoeus', '~> 0.3.3' to your Gemfile.

Anyway, I think this proves that the issue is not related to threading and is likely not a problem with this library.

@sferik sferik closed this Mar 9, 2013

@jfredson

This comment has been minimized.

jfredson commented Mar 20, 2013

Just wanted to chime in that I had the same issue and #2 fixed this for me.

More specifically in my case I was able to track down the issue to the following Twitter searches:

1.) Twitter.search("Thrill Me (Original Mix)") #works fine
2.) Twitter.search("#RR023") #works fine
3.) Twitter.search("Thrill Me (Original Mix) #RR023") #eof error

Working fine now that I've changed the default http adapter.

@jfredson

This comment has been minimized.

jfredson commented Mar 20, 2013

Hmmm, this doesn't seem to be applying to my rails console. Where would you apply that patch in order to get it to apply for both the server and the console? I put it in my application controller.

@veesahni

This comment has been minimized.

veesahni commented Mar 20, 2013

I was experiencing EOF errors every 30 mins or so since last night. I've switched to the typhoeus adapter, per @sferik's option 2 above and things have been quiet for the last 2 hours.

@BobWalsh

This comment has been minimized.

BobWalsh commented Mar 20, 2013

you might want to see #370 (comment)

@BobWalsh

This comment has been minimized.

BobWalsh commented Mar 20, 2013

after adding gem 'typhoeus', pasted code from solution 2 above and ran:

thetweets = Twitter.search('1git', :count => 10, :lang => "en", :result_type => "recent")

and got:
=> #<Twitter::SearchResults:0x007fb57d6d2088 @attrs={:statuses=>[], :search_metadata=>{:completed_in=>0.015, :max_id=>314467606818074624, :max_id_str=>"314467606818074624", :query=>"1git", :refresh_url=>"?since_id=314467606818074624&q=1git&lang=en&result_type=recent&include_entities=1", :count=>10, :since_id=>0, :since_id_str=>"0"}}>

10 minutes before, same request had got the end of file error.

@richhollis

This comment has been minimized.

richhollis commented Mar 21, 2013

When switching to typhoeus do you have to do all of the steps in #2? I just did step 2, switching the middleware and then got this error: typhoeus: disable_ssl_peer_verification is invalid

@graemecoleman

This comment has been minimized.

graemecoleman commented Mar 21, 2013

Apologies for the noobie question but, as someone who has limited experience of middleware, can someone help me to identify where the custom middleware stack in code example (2) should be placed in Rails (3.2.7) and, once it has been added, if anything else has to be done (e.g. rack middleware )? I have installed the Typhoeus gem, but the documentation (and Googling) is a bit on the light side when it comes to this.

I get a similar error to @richholis when I try to add the code to my initializer (where my keys are) in config/initializers, so I guess this is the wrong place...

Thanks!

@BobWalsh

This comment has been minimized.

BobWalsh commented Mar 21, 2013

What worked for me is adding the typhoeus gem to my gem file, and the code to my config/initializers/twitter.rb file that has my twitter credentials. May not be the "right" way to do it, but it works.

Bob Walsh

On Thursday, March 21, 2013 at 11:25 AM, Graeme C wrote:

Apologies for the noobie question but, as someone who has limited experience of middleware, can someone help me to identify where the custom middleware stack in code example (2) should be placed in Rails (3.2.7) and, once it has been added, if anything else has to be done (e.g. rack middleware )? I have installed the Typhoeus gem, but the documentation (and Googling) is a bit on the light side when it comes to this.
I get a similar error to @richholis when I try to add the code to my initializer (where my keys are) in config/initializers, so I guess this is the wrong place...
Thanks!


Reply to this email directly or view it on GitHub (#354 (comment)).

@richhollis

This comment has been minimized.

richhollis commented Mar 21, 2013

@BobWalsh @c0ley - I added mine to config/initializers/twitter.rb too but I still get that error. From reading all of these issues, I sort of got the impression that we aren't still 100% sure if this change does actually resolve the problem? Is there still a possibility something has changed on the twitter side because our project runs queries for several different users and has been running flawlessly for the past few months and then starts throwing out these errors yesterday. No other gems have been updated or changed so I do find myself wondering what has changed and if it is on the twitter side.

@graemecoleman

This comment has been minimized.

graemecoleman commented Mar 21, 2013

Thanks @BobWalsh - adding the code there seems to work, although I agree it might not be the "right" way to do it.

A word of warning, however - if you're using Typhoeus > 0.5.0 (i.e. the latest version), you need to add the following to the top of the file:

require 'typhoeus/adapters/faraday'

More details at typhoeus/typhoeus#226

Now to check it deploys correctly! Thanks all!

@natarius

This comment has been minimized.

natarius commented Mar 21, 2013

did 1. and 2. and it now seems to work

@richhollis

This comment has been minimized.

richhollis commented Mar 21, 2013

Thanks @c0ley - adding the require line does resolve the "typhoeus: disable_ssl_peer_verification is invalid" error.

@richhollis

This comment has been minimized.

richhollis commented Mar 22, 2013

My nightly batch which failed past two nights just ran with 1. and 2. patched and no errors at all seen.

@c0ri

This comment has been minimized.

c0ri commented Mar 23, 2013

I'm seeing this issue too. my setup as is:
$ openssl version
OpenSSL 0.9.8r 8 Feb 2011
faraday (0.8.4)
twitter (4.5.0, 4.4.4, 2.0.2)

btw.. here's the code doing it for me:

if Twitter.list_member?(MY_TWITTER_SCREEN_NAME, "bots", user_id)
puts "User #{user_name}(#{user_id}) is listed in " + MY_TWITTER_SCREEN_NAME + "/bots as a bot. Skipping."
next
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment