sinatra / sinatra

Classy web-development dressed in a DSL (official / canonical repo)
https://sinatrarb.com
MIT License
12.2k stars 2.08k forks source link

Server-Sent Events dont work on JRuby #962

Open Integralist opened 9 years ago

Integralist commented 9 years ago

I've uploaded an example repo that demonstrates the issue (of which there are two):

https://github.com/Integralist/Sinatra-SSE

The first issue is that SSE doesn't appear to work when using JRuby, but it does work when using MRI (note: the above repo is set to use MRI so it should work; so make sure to switch to JRuby and reinstall dependencies before testing)

Run with rackup -p 8000 and then you'll be able to access the application via http://localhost:8000/.

The home page loads a JavaScript file that opens a connection to /healthcheck.

The /healthcheck endpoint gets passed an even object from /update. Where /update is a POST endpoint that receives JSON.

You can test this using something like:

curl -v -H "Content-Type: application/json" -X POST -d '{"foo":"bar"}' http://127.0.0.1:8000/update

There are no obvious errors when using JRuby. The errors reported by JavaScript aren't helpful either.

The output in the terminal (for JRuby) is:

Puma 2.10.2 starting...
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:8000
127.0.0.1 - - [14/Jan/2015:16:11:55 +0000] "GET / HTTP/1.1" 200 190 0.0960
127.0.0.1 - - [14/Jan/2015:16:11:55 +0000] "GET /assets/scripts/connection.js HTTP/1.1" 304 - 0.0080
127.0.0.1 - - [14/Jan/2015:16:11:55 +0000] "GET /healthcheck HTTP/1.1" 200 - 0.0200
127.0.0.1 - - [14/Jan/2015:16:11:57 +0000] "GET / HTTP/1.1" 200 190 0.0380
127.0.0.1 - - [14/Jan/2015:16:11:58 +0000] "GET /assets/scripts/connection.js HTTP/1.1" 304 - 0.0160
127.0.0.1 - - [14/Jan/2015:16:11:58 +0000] "GET /healthcheck HTTP/1.1" 200 - 0.0130
127.0.0.1 - - [14/Jan/2015:16:12:01 +0000] "GET /healthcheck HTTP/1.1" 200 - 0.0100
127.0.0.1 - - [14/Jan/2015:16:12:04 +0000] "GET /healthcheck HTTP/1.1" 200 - 0.0060

The browser displays something like:

:8000/healthcheck:1 GET http://localhost:8000/healthcheck net::ERR_CONNECTION_REFUSED
connection.js:12 error Event {clipboardData: undefined, path: NodeList[0], cancelBubble: false, returnValue: true, srcElement: EventSource…}

The second issue (with MRI) is a random error that is reported:

NoMethodError: undefined method `join' for #<String:0x007f8cb19bee58>
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/sinatra-1.4.5/lib/sinatra/show_exceptions.rb:37:in `rescue in call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/sinatra-1.4.5/lib/sinatra/show_exceptions.rb:21:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/sinatra-1.4.5/lib/sinatra/base.rb:180:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/sinatra-1.4.5/lib/sinatra/base.rb:2014:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/sinatra-1.4.5/lib/sinatra/base.rb:1478:in `block in call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/sinatra-1.4.5/lib/sinatra/base.rb:1788:in `synchronize'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/sinatra-1.4.5/lib/sinatra/base.rb:1478:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/urlmap.rb:66:in `block in call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/urlmap.rb:50:in `each'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/urlmap.rb:50:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/tempfile_reaper.rb:15:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/lint.rb:49:in `_call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/lint.rb:37:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/showexceptions.rb:24:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/commonlogger.rb:33:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/sinatra-1.4.5/lib/sinatra/base.rb:217:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/chunked.rb:54:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/content_length.rb:15:in `call'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/thin-1.6.3/lib/thin/connection.rb:86:in `block in pre_process'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/thin-1.6.3/lib/thin/connection.rb:84:in `catch'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/thin-1.6.3/lib/thin/connection.rb:84:in `pre_process'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/thin-1.6.3/lib/thin/connection.rb:53:in `process'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/thin-1.6.3/lib/thin/connection.rb:39:in `receive_data'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/eventmachine-1.0.4/lib/eventmachine.rb:187:in `run_machine'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/eventmachine-1.0.4/lib/eventmachine.rb:187:in `run'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/thin-1.6.3/lib/thin/backends/base.rb:73:in `start'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/thin-1.6.3/lib/thin/server.rb:162:in `start'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/handler/thin.rb:19:in `run'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/server.rb:286:in `start'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/server.rb:147:in `start'
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/lib/rack/server.rb:147:in `start'                 
        /Users/markmcdonnell/.gem/ruby/2.0.0/gems/rack-1.6.0/bin/rackup:4:in `<top (required)>'
        /Users/markmcdonnell/.gem/ruby/2.0.0/bin/rackup:23:in `load'
        /Users/markmcdonnell/.gem/ruby/2.0.0/bin/rackup:23:in `<main>'

...this error occurs every once in a while. I've yet to find any rhyme or reason behind it.

kgrz commented 9 years ago

The error message is related to https://github.com/sinatra/sinatra/commit/b39d72d2a5b824b5f607b7825c4b076f527461a1

The fix is already in master branch. Until a new release is made, you can point the gem to master:

# Gemfile

gem 'sinatra', github: 'sinatra/sinatra'

Can you try the program on MRI with master branch and check if there's an error?

rkh commented 9 years ago

Can you confirm/deny whether this is fixed by using master?

Integralist commented 9 years ago

I will test this on Sunday and provide confirmation (apologies for the delay) see following comment...

Integralist commented 9 years ago

Hi @rkh sorry but it seems when I responded earlier, I did so without remembering what the actually problem was that this issue was related to. I've just realised that all the information you need was provided as part of my issue description...

"The fix is already in master branch. Until a new release is made, you can point the gem to master"

I was already using this as you can see in the example repo I originally provided https://github.com/Integralist/Sinatra-SSE/blob/master/Gemfile#L3

Can you try the program on MRI with master branch and check if there's an error?

I had already explained as part of the issue description that the issue was with JRuby and NOT MRI -> The first issue is that SSE doesn't appear to work when using JRuby, but it does work when using MRI (note: the above repo is set to use MRI so it should work; so make sure to switch to JRuby and reinstall dependencies before testing)

zzak commented 8 years ago

Does this issue still exist on the latest version of JRuby?

qbrossard commented 8 years ago

Yep. I just tested with the sinatra master branch and JRuby 9.0.5.0 and the result is exactly the same: the error callback gets executed.

zzak commented 8 years ago

Here's what I see in the console using latest JRuby 9.1.0.0, on WEBrick and puma:

# WEBrick
[2016-05-10 17:47:50] INFO  WEBrick 1.3.1
[2016-05-10 17:47:50] INFO  ruby 2.2.3 (2016-01-26) [java]
[2016-05-10 17:47:50] INFO  WEBrick::HTTPServer#start: pid=24642 port=8000
127.0.0.1 - - [10/May/2016:17:47:58 +0900] "POST /update HTTP/1.1" 200 - 0.1100
127.0.0.1 - - [10/May/2016:17:48:15 +0900] "GET /healthcheck HTTP/1.1" 200 - 0.0150
127.0.0.1 - - [10/May/2016:17:48:33 +0900] "GET /healthcheck HTTP/1.1" 200 - 0.0170
127.0.0.1 - - [10/May/2016:17:48:42 +0900] "GET /healthcheck HTTP/1.1" 200 - 0.0160
127.0.0.1 - - [10/May/2016:17:48:49 +0900] "GET /healthcheck HTTP/1.1" 200 - 0.0150
127.0.0.1 - - [10/May/2016:17:48:50 +0900] "GET /favicon.ico HTTP/1.1" 404 501 0.0250
127.0.0.1 - - [10/May/2016:17:49:08 +0900] "GET /healthcheck HTTP/1.1" 200 - 0.0060
^C[2016-05-10 17:49:39] INFO  going to shutdown ...
[2016-05-10 17:49:39] INFO  WEBrick::HTTPServer#start done.

and:

# puma
Puma starting in single mode...
* Version 3.4.0 (jruby 9.0.5.0 - ruby 2.2.3), codename: Owl Bowl Brawl
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:8000
Use Ctrl-C to stop
127.0.0.1 - - [10/May/2016:17:50:30 +0900] "POST /update HTTP/1.1" 200 - 0.0760
127.0.0.1 - - [10/May/2016:17:50:35 +0900] "GET /healthcheck HTTP/1.1" 200 - 0.0270
^C- Gracefully stopping, waiting for requests to finish
=== puma shutdown: 2016-05-10 17:50:40 +0900 ===
Goodbye!

Here's what I get in the browser console:

error error { target: EventSource, isTrusted: true, currentTarget: EventSource, eventPhase: 2, bubbles: false, cancelable: false, defaultPrevented: false, timeStamp: 1462870399318871, originalTarget: EventSource, explicitOriginalTarget: EventSource, NONE: 0 }

I have no idea why the error callback is triggered. Ugh.

zzak commented 8 years ago

Well, now I can reproduce it with MRI as well.

dentarg commented 1 year ago

Someone should try this again 7 years later with recent versions of everything :)