rubysinatraeventmachinetweetstream

How To Run EventMachine and Serve Pages In Sinatra?


I'm building a Sinatra app that uses TweetStream (which listens for Tweets using EventMachine). I would also like the app to serve pages like a normal Sinatra app but it seems like Sinatra can't "listen" for page requests when it's "listening" for Tweets.

Is this something I can fix by using a different server or structuring my app in a different way? I've tried using WebBrick and Thin.

Here is basically what I'm doing:

class App < Sinatra::Base

  # listening for tweets
  @client = TweetStream::Client.new
  @client.track(terms) do |status|
    # do some stuff when I detect terms
  end  

  get '/' do
    "Here's some page content!"
  end

end

Solution

  • You can mount Sinatra apps within eventmachine (providing you you a awebserver that supports EM i.e., Thin). You should then have full access to the EM reactor loop from your Sinatra app, as well as allowing any other EM plugins to run too.

    The Sinatra recipes have a good example:

    http://recipes.sinatrarb.com/p/embed/event-machine

    here is a very stripped down version of the code:

    require 'eventmachine'
    require 'sinatra/base'
    require 'thin'
    
    def run(opts)
    
      EM.run do
        server  = opts[:server] || 'thin'
        host    = opts[:host]   || '0.0.0.0'
        port    = opts[:port]   || '8181'
        web_app = opts[:app]
    
        dispatch = Rack::Builder.app do
          map '/' do
            run web_app
          end
        end
    
        unless ['thin', 'hatetepe', 'goliath'].include? server
          raise "Need an EM webserver, but #{server} isn't"
        end
    
        Rack::Server.start({
          app:    dispatch,
          server: server,
          Host:   host,
          Port:   port
        })
      end
    end
    
    class HelloApp < Sinatra::Base
    
      configure do
        set :threaded, false
      end
    
      get '/hello' do
        'Hello World'
      end
    
      get '/delayed-hello' do
        EM.defer do
          sleep 5
        end
        'I\'m doing work in the background, but I am still free to take requests'
      end
    end
    
    run app: HelloApp.new