lifo / cramp

Real-time web application framework in Ruby
http://cramp.in
MIT License
1.5k stars 121 forks source link

Streaming does not work #23

Open lennartkoopmann opened 13 years ago

lennartkoopmann commented 13 years ago

I have this code:

# hello_world.ru
require "rubygems"
require 'cramp'

class HomeAction < Cramp::Action
  def start
    render "Hello World"
    sleep 5
    render "foo"
    finish
  end
end

run HomeAction

I run this with thin --timeout 0 -R hello_world.ru start but nothing is streamed:

local ~$ curl -v http://127.0.0.1:3000
* About to connect() to 127.0.0.1 port 3000 (#0)
*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.21.0 (x86_64-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
> Host: 127.0.0.1:3000
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: text/html
< Connection: keep-alive
< Server: thin 1.2.11 codename Bat-Shit Crazy
* no chunk, no close, no size. Assume close to signal end
< 
* Closing connection #0
Hello Worldfoo

It takes exactly the sleep(5) seconds to get the result returned.

I have the same problem when running in a clamp skeleton application as described in the docs. (using Bundler)

Server output:

local ~/workspace/crampy$ thin --timeout 0 -R hello_world.ru start -V
>> Thin web server (v1.2.11 codename Bat-Shit Crazy)
>> Tracing ON
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:3000, CTRL+C to stop
GET / HTTP/1.1
User-Agent: curl/7.21.0 (x86_64-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
Host: 127.0.0.1:3000
Accept: */*

HTTP/1.1 200 OK
Content-Type: text/html
Connection: keep-alive
Server: thin 1.2.11 codename Bat-Shit Crazy

Hello World
foo
^C>> Stopping ...

Versions:

local ~/workspace/crampy$ ruby -v
ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-linux]
local ~/workspace/crampy$ thin -v
thin 1.2.11 codename Bat-Shit Crazy

Gems:

cramp (0.15.1)
http_router (0.10.2)
async-rack (0.5.1)
thin (1.2.11)

I am not sure where to start debugging so any help would be very appreciated! Thank you!

lennartkoopmann commented 13 years ago

Linux nb-lkoopmann 2.6.35-30-generic #56-Ubuntu SMP Mon Jul 11 20:01:08 UTC 2011 x86_64 GNU/Linux

lifo commented 13 years ago

Could you please try curl with -N option:

curl -N -v http://127.0.0.1:3000

lennartkoopmann commented 13 years ago
local ~$ curl -N -v http://127.0.0.1:3000
* About to connect() to 127.0.0.1 port 3000 (#0)
*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.21.0 (x86_64-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
> Host: 127.0.0.1:3000
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: text/html
< Connection: keep-alive
< Server: thin 1.2.11 codename Bat-Shit Crazy
* no chunk, no close, no size. Assume close to signal end
< 
Hello Worldfoo* Closing connection #0

Thanks!

lennartkoopmann commented 13 years ago

The Twitter stream API for example is working and streaming for me with the same curl call:

local ~$ curl -v http://stream.twitter.com/1/statuses/sample.json -umyuser:mypass
* About to connect() to stream.twitter.com port 80 (#0)
*   Trying 199.59.148.138... connected
* Connected to stream.twitter.com (199.59.148.138) port 80 (#0)
* Server auth using Basic with user '_lennart'
> GET /1/statuses/sample.json HTTP/1.1
> Authorization: [REMOVED]
> User-Agent: curl/7.21.0 (x86_64-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
> Host: stream.twitter.com
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: application/json
< Transfer-Encoding: chunked
< Server: Jetty(6.1.25)
< 
{"in_reply_to_screen_name":null,"text":"What's for breakfast tho?","in_reply_to_user_id_str":null,
....
lifo commented 13 years ago

It's likely because Twitter API results would fill the curl buffer very quickly, so you'd see the results almost instantly.

lennartkoopmann commented 13 years ago

Okay. So you think it is a problem with curl? (Just to make sure: It was still not working with the curl -N switch)

lifo commented 13 years ago

Ah I thought -N did the trick. I'll have a look later today.

Thanks!

koudelka commented 13 years ago

I suspect the problem is due to the sleep call locking up the EM reactor while the 'Hello World' render has been buffered to the output stream, but not yet flushed.

Instead of holding up the whole reactor with sleep, try EM::add_timer, like so:

# hello_world.ru
require "rubygems"
require 'cramp'

class HomeAction < Cramp::Action

  def start
    render "Hello World"
    EventMachine::add_timer(5) do
      render "foo"
      finish
    end
  end
end

run HomeAction