How to serve socket.io client files in rails - ruby-on-rails

I am writing a rails app, and I would like to use node.js and socket.io to integrate a chat feature into my app. I plan on having my rails app deployed on one server, and my chat deployed on a much smaller server (to save money). My reasoning for this is, it is OK if a chat message takes 30s to send, but it is not OK for a page to take 30s to load.
Anyway, in order for this to work, I need Rails to server the socket.io client files. If my small node server serves the client files, then the small server will bottleneck the larger one. I have a basic chat prototype up and running, but it only works with node serving the client files. What do I have to do in order to have rails serve the client files?
Thanks in advanced.

So here is the solution I decided upon. Instead of figuring out what client files I need to serve, I decided to let the Node server handle the client javascript. In order to ensure that the Node server does not bottleneck the Rails server, I lazy load the socket.io-client file. The relevant coffee script is:
$ ->
$.getScript('http://localhost:8080/socket.io/socket.io.js')
.done (script, textStatus) ->
socket = io.connect('http://localhost:8080')
setupSocket(socket)
Where http://localhost:8080 is your Node host/port. setupSocket is a function I wrote that handles setting all the event handlers.

Most probably you are running into the "Same Origin Policy" restriction. (Check your console log) Your main page is downloaded from the RoR host, so your scripts can only initiate a connection to that host.
In other words, this may not be possible.

Related

How to keep the application alive without a client

My goal is to send an email out every 5 min from my application even if there isn't a browser open to the application.
I'm using FluentScheduler to manage the tasks; which works up until the server decides to kill the application from inactivity.
My big constraints are:
I can't touch the server. It is how it is and I have to work around it.
I can't rely on a client refreshing a browser or anything else along the lines of using client side scripts.
I can't use any scheduler that uses a database.
What I have been focusing on is trying to create an artificial postback.
Note: The server is load balanced, so a solution could use that
Is there any way that I can keep my application from getting killed by the server?
You could use a monitoring service like https://www.pingdom.com/ to ping the server at regular intervals. Just make sure it hits an endpoint that invokes .NET code and not a static resource.

Callback (or equivalent) when container w/ Rails app finishes booting?

I have a docker container containing a rails app. Running the container starts a script similar to this: https://github.com/defunkt/unicorn/blob/master/examples/init.sh, which does some busy work and then reaches out to a unicorn.rb script similar to this: https://github.com/defunkt/unicorn/blob/master/examples/unicorn.conf.rb.
I have a clojure web app that can tell this container to run. The request to do this is nonblocking, and the user of the site will somehow be notified when the rails app is ready to receive requests.
I can think of various hacky ways to do this, but is there an idiomatic way to have the container let me know when the unicorn rails app is ready to receive web requests?.
I'd like to have it hit some callback url in my app but I'm open to other options. Thanks!
I don't get why you need to do it that way. Couldn't you just perform HTTP requests to the rails part (eg http:://my_page.com/status) and handle the response accordingly?

ruby on rails chat application over port 80 which is hosting site agnostic(no flash and websockets)

Wanted to build a chat like application(i.e bidirectional message passing to multiple connected clients). Looked at the Faye gem but it opens a new port apart from port 80.
The big problem is that if the client is behind firewall all access to other ports except 80 are restricted and not all the hosting sites provide the support.
The ActionController::Live component does not have any mechanism to register the clients so that the message can not be passed to the registered clients on a specific event occurance.
Looking for a solution where the alive clients are stored in a collection(array or somthing like that) and when any of the alive client sends a message then the collection can be iterated and the messages can be written on it. All of these must happen only through port 80.
Good question - having implemented something similar, let me explain how it works:
Connections
A "live" web application is not really "live" at all - it's just got a persistent request; meaning it still works exactly the same as a "normal" Rails app, except clients don't close the connection (hence why you're interested in opening another port)
The way you handle the request is where the magic happens. This is as much to do with the client-side, as it is with Rails (server-side)
Clients
When you connect to a "chat" application, your browser is opening a live connection with the server. This will typically be done with either server sent events (Ajax long polling), or web sockets
The way this works is to open the connection using the normal Rails ActionDispatch middleware, and then allow you to connect
If you've played with ActionController::Live functionality, you'll find that it's not a typical controller-action. It's actually a separate technology (like resque or Redis) which you call from another controller action. This gives room to do cool things with
Server
The way you'd handle something like this is to separate the "live" functionality and the "normal" Rails app. It's one of the current down-falls of Rails - in that it's probably better to implement something like nodeJS with socket.io to handle the live data (with an endpoint like chat.yourapp.com), whilst using Rails to handle authentication & authorization
From a server perspective, its job is to handle incoming & outgoing requests -- not to handle persistent connections. So I guess you may want to look at ways you could "outsource" the websocket connectivity. Admittedly, my experience is slightly thin in this area, so you may do well searching the net
Solutions
We've had a lot of success using a third-party system called Pusher
This is a web socket system which allows you to open a persistent connection as a client, and integrates with Rails in a similar way to Redis (you can push to it)
This means you can host the "chat" application with Rails (http://yourapp.com/chat), send the messages to your Rails app (http://yourapp.com/chat/send), and handle the incoming chats from pusher (or similar)
Maybe you want to use my open source comet web server (https://github.com/TorstenRobitzki/Sioux). There is a ruby web chat example. I use this to implement an interactive role playing map with rails (http://dungeonpilot.com).

Rails and Node in the same app on Heroku?

I'm building a Rails application that deals with file uploads through CarrierWave. Currently, larger file uploads block the server for a significant amount of time. I have seen solutions like the s3-swf-upload-plugin gem that skip the local server and send files straight from the browser to S3, but this would require some modifications for pre-generating unique filenames and synchronizing them with the database. I'm sure it wouldn't be too much trouble, but Heroku's new Cedar stack gave me the idea of offloading these long running requests to a node.js instance running in the same app. I'm not very experienced with these kinds of things, so excuse my wording if it's a bit off.
Would something like this be possible? How would you configure things such that certain requests (ones involving file uploads, in this case) would be handled by a node app bundled in the same heroku repository as the main rails app?
I don't think it's possible to mix Rails and Node in the same app. However, you could get roughly the same functionality by using two separate apps that communicate with each other.
You can use ENV['DATABASE_URL'] to determine your database connection string. Use the heroku console to set it as an ENV variable for your Node app (e.g. heroku config:add OTHER_DB=your_connection_string) should then be able to use the same connection string to connect to the same database from your other heroku app. You could even access it outside of heroku if you have a dedicated database, see: http://devcenter.heroku.com/articles/external-database-access
For seamless integration between the two apps, you could have a form rendered by the Rails app post to a URL of the Node app. In addition to the file upload, include in that form via hidden input fields any other variables you need to communicate to the Node app. When the upload to the Node app is done, it could redirect the client back to the Rails app, passing any status or variables as get parameters.
Run the two apps under two subdomains of the same domain and you could even share cookies between them.
You need two apps. I am doing exactly what's described in this question. I wanted large streaming uploads, and since Rack writes downloads to a temp file before passing them through to the handler, it is not possible to do this with Rails.
Node.js, on the other hand, does this beautifully. So there are two Heroku apps, the Rails web app and the Node.js (Express) web app. The Rails web app uses SWFUpload as the client-side solution. The Rails app and the Node.js app both have a secret key as a Heroku config variable. When it's time for the user to upload, client-side Javascript requests an upload URL from the Rails server. The Rails server forms an upload URL with an Expires parameter and computes a signature using the secret key. The client-side Javascript handler passes this URL along to SWFUpload (upload_url property). The user selects the files to upload, and SWFUpload starts posting them to the upload_url. The Node.js app verifies that the URL is not expired and that the signature is valid. It processes the form data with the formidable library.
One other detail. Flash requires the Node.js app to serve a crossdomain.xml that permits the cross-site request.
My Node.js app doesn't touch the database; but if it did I would share DATABASE_URL as previously suggested. Note that you can't share a DATABASE_URL outside of Heroku unless you have a dedicated DB. The DATABASE_URLs for shared databases are not reachable from outside Heroku (unlike some other services like RedisToGo).

How to check the cause for a HTTP request latency/waiting time?

I issue a simple GET request to my server, and it's coming back after ~1.2 seconds on average (using firebug NET tab, the "waiting for reqponse" part- not even the whole reponse time)
My ping to the server is 0.250
Using Passenger with rails 2.3.3, in the rails log the request is taking ~0.023
My server is on GoDaddy, so I checked their homepage with firebug also- the "waiting for reqponse" time for their page is ~0.320
Worst case should be around 0.4... so where did I lose the other 0.8 seconds?
What else can I check?
Edit:
Seems like it's unrelated to rails-
An image request (that only apache responds to, doest hit the rails at all) takes ~1.2 seconds also
GoDaddy may have a reverse-proxy between you and your HTTP server.
They may be doing something like sending you the response headers right away, then possibly serving you the contents of the response from cache.
So, from the standpoint of your HTTP server, the response is transmitted. Then it goes to GoDaddy's reverse-proxy, then finally to your web browser.
Try setting PassengerPoolIdleTime to 0 in your Servers or VHosts configuration.
Maybe your server is shutting down the application instances to fast and spawns a new instance with every request which usualy takes quite long.
Take a look at the documentation for more information on this setting:
http://modrails.com/documentation/Users%20guide%20Apache.html#PassengerPoolIdleTime
Where your files are hosted from for GoDaddy is not the same as where their homepage is hosted from.
Have you checked other pages you have hosted on the same server? Possibly due to database connections or "slow" connections like that can cause the page to take awhile before it's sent back to the client.
Doesn't sound like it is your problem, but the ISP's.
Can you do a wget to an internal ip/port to your rails app directly (or apache) from the same server?
That will tell you if the probaby is in the app stack or further upstream.
If you can, you can use apache tool, called ab "apache benchmark" to help.
The key is having a ssh access to your computer.

Resources