Long polling (comet) on Rails

Hello!

I’d like to share some concepts with community regarding asynchronous
operations in Rails, hoping for feedback and advice.
We (Helicon Tech) currently work on Ruby
on Rails implementation for
Microsoft IIS. Our goal is to make RoR available for shared Windows
hostings and developers. We currently work with several small hostings
to implement RoR shared hosting solution with them as proof of concept.

So I was thinking… since we already have a working asynchronous server
implementation and asynchronous (after some tweaking) implementation of
FastCGI, we may utilize it to bring async into the RoR applications.

Our concept is quite easy. I will show it on a simple chat application
example: Our server creates a fiber and puts a Rack call into the fiber
body, so all RoR code, like controller is executed inside a fiber. There
is a script to wait for new messages, which simply yields (suspends) a
fiber. So there could be number, maybe thousands of suspended fibers at
a time. When new message is received it is put into the storage and all
fibers waiting for it are resumed. They process messages, return
responses to their clients and then clients makes another request to a
wait script.

We have working proof of concept for it, but I need a feedback from the
community. Whether this future is needed at all and what possible
problems and flaws I need to take into consideration?

Also I am thinking on how to extend this concept to bring more
asynchronous operations into RoR. Imagine we have some time consuming
operation in the script. Like we are requesting whether forecast data
from remote server for analysis. We could start an asynchronous http
request operation, setting up a resume of current fiber as a callback,
and then suspend current fiber, allowing other requests to be served.
Such system could handle much more load that a synchronous system.
Unfortunately I cannot find appropriate concept of asynchronous
operations for Ruby – how to do an async HTTP request? Some use
'eventmachine' to do this. But while providing some asynchronous
operation support inside event loop, the loop itself completely blocks
execution thread. I think we may try to put our entire client-server
conversation into the event loop, need to try it first.
Anyway any feedback and suggestions are greatly appreciated.

Thank you!

Hello!

I’d like to share some concepts with community regarding asynchronous
operations in Rails, hoping for feedback and advice.
We (Helicon Tech) currently work on Ruby
on Rails implementation for
Microsoft IIS. Our goal is to make RoR available for shared Windows
hostings and developers. We currently work with several small hostings
to implement RoR shared hosting solution with them as proof of concept.

So I was thinking… since we already have a working asynchronous server
implementation and asynchronous (after some tweaking) implementation of
FastCGI, we may utilize it to bring async into the RoR applications.

Our concept is quite easy. I will show it on a simple chat application
example: Our server creates a fiber and puts a Rack call into the fiber
body, so all RoR code, like controller is executed inside a fiber. There
is a script to wait for new messages, which simply yields (suspends) a
fiber. So there could be number, maybe thousands of suspended fibers at
a time. When new message is received it is put into the storage and all
fibers waiting for it are resumed. They process messages, return
responses to their clients and then clients makes another request to a
wait script.

We have working proof of concept for it, but I need a feedback from the
community. Whether this future is needed at all and what possible
problems and flaws I need to take into consideration?

Personally I worry slightly about ruby's ability to handle several
thousand IO streams. Does it use efficient select alternatives like
epoll or queues on platforms that support them? The last time I did
something like this I wrote the comet part as a C++ daemon. When
events like a message being posted occurred, the rails code notified
the C++ daemon, that in turn notified any clients that had registered
an interest in the relevant event.

I'd also worry about how your model handles the case where your web
front ends are spread across several servers - if the request with a
new chat message arrives at server A but some of the waiting fibers
are on server B, how does the message get passed across ?

Also I am thinking on how to extend this concept to bring more
asynchronous operations into RoR. Imagine we have some time consuming
operation in the script. Like we are requesting whether forecast data
from remote server for analysis. We could start an asynchronous http
request operation, setting up a resume of current fiber as a callback,
and then suspend current fiber, allowing other requests to be served.
Such system could handle much more load that a synchronous system.
Unfortunately I cannot find appropriate concept of asynchronous
operations for Ruby – how to do an async HTTP request? Some use
'eventmachine' to do this. But while providing some asynchronous
operation support inside event loop, the loop itself completely blocks
execution thread. I think we may try to put our entire client-server
conversation into the event loop, need to try it first.
Anyway any feedback and suggestions are greatly appreciated.

I think with event machine you do pretty much have to give yourself
over entirely to event machine and do everything using the event
driven mechanisms it provides.

Fred

Thank you Fred for your answers!

Personally I worry slightly about ruby's ability to handle several
thousand IO streams. Does it use efficient select alternatives like

Non blocking IO is not only needed when you plan to implement chat
application. It is also a god thing to consider if your application
have to work in highly concurrent environment, like shared hosting
servers. Old technique of dedicating a process for every client
request has proven wrong. Additionally non blocking IO solver problems
of slow client and slow operations within Ruby script.

epoll or queues on platforms that support them? The last time I did
something like this I wrote the comet part as a C++ daemon. When
events like a message being posted occurred, the rails code notified
the C++ daemon, that in turn notified any clients that had registered
an interest in the relevant event.

I'd also worry about how your model handles the case where your web
front ends are spread across several servers - if the request with a
new chat message arrives at server A but some of the waiting fibers
are on server B, how does the message get passed across ?

Spreading nodes completely depends on a backend used to store and pass
messages - whether it would be RabbitMQ, database, etc. We only added
non blocking eventmachine support. We have almost all peaces working,
except ability to push data from the script. Our worker uses Rack to
interact with Rails, and Rack does not seem to provide any way to
return partial data to the server. So there is no ability to flush
some part of response to client and send a remaining part later. Still
working on a solution. Possibly the protocol have to be improved.

I think with event machine you do pretty much have to give yourself
over entirely to event machine and do everything using the event
driven mechanisms it provides.

Yes, already implemented it this way. Entire server loop within a
worker is now replaced by an eventloop. Will see how it handle the
load.

Thanks again!

Quoting Yaroslav Govorunov <govorunov@gmail.com>:
[snip]

Spreading nodes completely depends on a backend used to store and pass
messages - whether it would be RabbitMQ, database, etc. We only added
non blocking eventmachine support. We have almost all peaces working,
except ability to push data from the script. Our worker uses Rack to
interact with Rails, and Rack does not seem to provide any way to
return partial data to the server. So there is no ability to flush
some part of response to client and send a remaining part later. Still
working on a solution. Possibly the protocol have to be improved.

It is my understanding that flushing partial responses in implemented in Rails
3.1.

HTH,
  Jeffrey