Ruby a good choice for CGI?

N

Nick Dr

Ive been messing around with Ruby for a few weeks now, and I'm fairly
comfortable with the language itself, but now I want to host a *very*
tiny app on the net, and I'm getting very overwhelmed with the massive
array of frameworks and technologies available.

I'll describe what I'm trying to, and maybe someone here can just point
me in the right direction and spare me weeks of wading through doc to
find out all about each of these things.

I've written a small HTML/JQuery page that displays a simple UI on a
canvas element. The user clicks on pictures of buttons and the JQuery
posts a string to the server. I need some server side code - hopefully
ruby b/c i like the syntax, and i've heard bad things about PHP - that
will take the command from the POST, hit a MySQL db, and return a string
response. The JQuery takes the string response and updates the canvas.

Really simple right? I already have the HTML/JQuery/Canvas-draw. I've
already got the Ruby code itself, including the MySQL part.

I went to host it, and figured I'd try it at home before I spent any
money. I installed Apache on my Ubuntu box, dropped the Ruby files into
the cgi-bin folder, used the ruby cgi lib in my script and it all
worked. Then the plane crashed in the mountain.

I started reading online and people said pure CGI was way too slow b/c
I'll be loading and disposing of all my code and db connections each
request. That sounds bad. So what do I do? I've be told things about
FastCGI, Passenger, mod_ruby, Rack, Sinatra, Camping, etc. and I can't
even figure out which one I need!

Can someone point me in the right direction here? My app is VERY small.
Practically no code, no HTML output. All I need is to execute the 2 or 3
Ruby functions I already have, on the net, with some basic
cookie/session support. What's the least headache(and not terribly slow)
way to do this?
 
W

Walton Hoops

-----Original Message-----
From: (e-mail address removed) [mailto:[email protected]]

Ive been messing around with Ruby for a few weeks now, and I'm fairly
comfortable with the language itself, but now I want to host a *very*
tiny app on the net, and I'm getting very overwhelmed with the massive
array of frameworks and technologies available.

I'll describe what I'm trying to, and maybe someone here can just point
me in the right direction and spare me weeks of wading through doc to
find out all about each of these things.

I've written a small HTML/JQuery page that displays a simple UI on a
canvas element. The user clicks on pictures of buttons and the JQuery
posts a string to the server. I need some server side code - hopefully
ruby b/c i like the syntax, and i've heard bad things about PHP - that
will take the command from the POST, hit a MySQL db, and return a
string
response. The JQuery takes the string response and updates the canvas.

Really simple right? I already have the HTML/JQuery/Canvas-draw. I've
already got the Ruby code itself, including the MySQL part.

I went to host it, and figured I'd try it at home before I spent any
money. I installed Apache on my Ubuntu box, dropped the Ruby files into
the cgi-bin folder, used the ruby cgi lib in my script and it all
worked. Then the plane crashed in the mountain.

I started reading online and people said pure CGI was way too slow b/c
I'll be loading and disposing of all my code and db connections each
request. That sounds bad. So what do I do? I've be told things about
FastCGI, Passenger, mod_ruby, Rack, Sinatra, Camping, etc. and I can't
even figure out which one I need!

Can someone point me in the right direction here? My app is VERY small.
Practically no code, no HTML output. All I need is to execute the 2 or
3
Ruby functions I already have, on the net, with some basic
cookie/session support. What's the least headache(and not terribly
slow)
way to do this?


DISCLAIMER: I don't actually use Ruby for webapps

CGI is ok, if and only if your web traffic is very low. If you
Expect a lot of traffic, or your traffic will be coming in bursts, you
definitely want to figure something else out. For something as simple
as you seem to be describing, I would recommend either mod_ruby, or
fastcgi. Mod_ruby is akin to mod_php5 or mod_python where the Ruby
interpreter is actually imbedded in the Apache server. FastCGI on
the other hand is similar to CGI, except that the process is reused
for requests rather than starting a new one for each request.

I'm not sure which will be easier, but either should be able
to handle what you need, and I think both should be fairly simple setups.

Both are available in Ubuntu via:
sudo apt-get install libapache2-mod-fastcgi
sudo apt-get install libapache2-mod-ruby

I hope this helps!
 
J

Jesús Gabriel y Galán

I started reading online and people said pure CGI was way too slow b/c
I'll be loading and disposing of all my code and db connections each
request. That sounds bad. So what do I do? I've be told things about
FastCGI, Passenger, mod_ruby, Rack, Sinatra, Camping, etc. and I can't
even figure out which one I need!

Can someone point me in the right direction here? My app is VERY small.
Practically no code, no HTML output. All I need is to execute the 2 or 3
Ruby functions I already have, on the net, with some basic
cookie/session support. What's the least headache(and not terribly slow)
way to do this?

I've been doing little apps with Sinatra and I'm very happy with it.
Pretty simple if you just need to implement 2 or 3 get requests:

require 'sinatra/base'
class MyClass < Sinatra::Base
get '/' do
"hello world"
end
end
MyClass.run!

Any rack-based framework (as Sinatra) can be deployed in a number of
ways including Phussion Passenger (apache) or most ruby webservers,
like Thin.

Hope this helps,

Jesus.
 
D

David Masover

I've written a small HTML/JQuery page that displays a simple UI on a
canvas element. The user clicks on pictures of buttons and the JQuery
posts a string to the server. I need some server side code - hopefully
ruby b/c i like the syntax, and i've heard bad things about PHP - that
will take the command from the POST, hit a MySQL db, and return a string
response. The JQuery takes the string response and updates the canvas.

That sounds tailor-made for Sinatra. However, you should learn something about
REST, first -- are you sure POST is appropriate?
I've
already got the Ruby code itself, including the MySQL part.

Why MySQL specifically? Why not go with something database-agnostic, like
Datamapper, Sequel, or ActiveRecord?

But hey, if you've already got it, it works.
I've be told things about
FastCGI, Passenger, mod_ruby, Rack, Sinatra, Camping, etc. and I can't
even figure out which one I need!

FastCGI is obsolete, so scratch that.

Passenger and mod_ruby are essentially the same thing, IIRC. But my
understanding is that Passenger works with Rack, which doesn't feel at all
like CGI. So these might be deployment options, but they have nothing to do
with how you write and develop your app.

So among your options are Sinatra and Camping. Camping is by _why, who seems
to have disappeared, but I'm sure someone's maintaining it... What I like
about Sinatra is the sheer simplicity of:

get '/' do
'Hello, world!'
end

In your case, assuming you still want a POST, it'll probably be something
like:

post '/wherever' do
# build your string from the database and return it
end

Once you've got it working on localhost, if you can find a managed host
that'll just let you upload a Rack app (especially if they know about
Sinatra), do that. Or you could do it yourself -- right now, I'm liking nginx
and Unicorn, which is what Github uses:

http://github.com/blog/517-unicorn

On the other hand, you could technically deploy this with Passenger. Some
people find it easier, but I like deploying with Capistrano anyway.
some basic
cookie/session support.
http://www.sinatrarb.com/faq.html#sessions

What's the least headache(and not terribly slow)
way to do this?

My vote is Sinatra.
 
M

Marnen Laibow-Koser

David Masover wrote:
[...]
FastCGI is obsolete, so scratch that.

Passenger and mod_ruby are essentially the same thing, IIRC.

You do not RC. :) Passenger is the same as mod_rails. mod_ruby is an
older module, suitable for CGI scripts but not Rails (and therefore I
would assume it's not suitable for Sinatra).
But my
understanding is that Passenger works with Rack, which doesn't feel at
all
like CGI. So these might be deployment options, but they have nothing to
do
with how you write and develop your app.

So among your options are Sinatra and Camping. Camping is by _why, who
seems
to have disappeared, but I'm sure someone's maintaining it...

There's also Merb, which is used by SproutCore sort of in the way the OP
is describing.
What I
like
about Sinatra is the sheer simplicity of:

get '/' do
'Hello, world!'
end

That looks nice! I plan to try Sinatra if I run into a project for
which Rails is excessive.

In your case, assuming you still want a POST, it'll probably be
something
like:

post '/wherever' do
# build your string from the database and return it
end

Once you've got it working on localhost, if you can find a managed host
that'll just let you upload a Rack app (especially if they know about
Sinatra), do that. Or you could do it yourself -- right now, I'm liking
nginx
and Unicorn, which is what Github uses:

http://github.com/blog/517-unicorn

On the other hand, you could technically deploy this with Passenger.
Some
people find it easier, but I like deploying with Capistrano anyway.

They're not mutually exclusive. Cap + Passenger is a great combination.
My vote is Sinatra.

Best,
 
B

Bill Kelly

From: "Nick Dr said:
Can someone point me in the right direction here? My app is VERY small.
Practically no code, no HTML output. All I need is to execute the 2 or 3
Ruby functions I already have, on the net, with some basic
cookie/session support. What's the least headache(and not terribly slow)
way to do this?

Others have already mentioned Sinatra, which looks nice. Another
framework which also allows starting very simple is Ramaze:
[ http://ramaze.net/ ]


require 'ramaze'

class MainController < Ramaze::Controller
def index
"Hello, World! Server clock reads: #{Time.now}"
end
end

Ramaze.start :port => 9001, :adapter => :webrick


At this point the HTTP server is running on a custom port. However,
it's not difficult to integrate that with the webserver, as described
here: http://wiki.ramaze.net/Deployment


Regards,

Bill
 
D

David Masover

get the benefits of mod_ruby (not restarting the interpreter with each
request)

I'm confused. Wasn't mod_ruby the one which restarts the interpreter with each
request? I also don't know of _any_ Rack handler that restarts the interpreter
with each request.

The supposed technical advantages of Passenger are that you're building on
Apache, that it's actually somewhat production-ready but doesn't require
complex reverse proxies, and it has something to do with Ruby Enterprise
Edition.

I'm curious, actually... I get why people might choose thin (really quick
responses, so no real multitasking required -- keep it simple), mongrel (old-
ish and proven), unicorn (simple, reliable, prefork is proven), ebb (C for
speed, and threads may be more efficient than forking), etc etc.

I don't really see the case for Passenger over these, other than simplicity of
deployment. Am I missing anything?
 
M

Marnen Laibow-Koser

David Masover wrote:
[...]
The supposed technical advantages of Passenger are that you're building
on
Apache,

Sort of, although I think you can use it with Nginx and Thin.
that it's actually somewhat production-ready

Strike the "somewhat".
but doesn't require
complex reverse proxies,

Right. It also doesn't require clustered Mongrels. It's about as easy
to set up as mod_php.
and it has something to do with Ruby Enterprise
Edition.

It's written by the same people, and I believe it can take advantage of
some Ruby EE optimizations. But you can use it just as well with MRI
(although I'm not sure why you would -- EE is much faster).
I'm curious, actually... I get why people might choose thin (really
quick
responses, so no real multitasking required -- keep it simple), mongrel
(old-
ish and proven), unicorn (simple, reliable, prefork is proven), ebb (C
for
speed, and threads may be more efficient than forking), etc etc.

I don't really see the case for Passenger

Incredible ease of configuration, EE optimizations. AFAIK, Passenger
has no serious competition on either of these points.
over these, other than
simplicity of
deployment.

Not app deployment so much as configuration. It really is about as easy
to set up as mod_php. I don't know of any other Rails/Rack server setup
for which that can be said.

Am I missing anything?

You're missing just about everything. :) Personally, I'm not sure what
the case *against* Passenger is, unless you're using Windows or JRuby.

Didn't 37signals switch to Passenger some time ago?

Best,
 
B

Brian Candler

David said:
I'm confused. Wasn't mod_ruby the one which restarts the interpreter
with each
request?

That would be CGI. Each incoming request forks off a new CGI handler,
which processes one request then terminates.

With the old mod_ruby, each Apache HTTP worker has an interpreter. If
Apache decides to fire up 20 workers because it's handling 20 concurrent
connections, that's 20 ruby interpreters. That may be wasteful if there
are mixed ruby and regular HTTP requests.

Phusion Passenger keeps a pool of Ruby processes, independent of the
httpd workers/threads, and picks a free worker to dispatch each ruby
request into. This makes it similar in some ways to fastcgi, but it's
much easier to set up.
I also don't know of _any_ Rack handler that restarts the
interpreter
with each request.

You can run rack as a CGI, I belive. You would not be advised to.
something to do with Ruby Enterprise
Edition.

That's the fork-friendly garbage collection. Passenger also prepares a
preloaded ruby interpreter with your app and forks it when it needs to
increase the size of the pool, rather than starting with a fresh ruby
instance which would have to read all the libraries in. Advantages: much
faster startup, and much more RAM sharing between ruby processes, so
less total RAM used.
I'm curious, actually... I get why people might choose thin (really
quick
responses, so no real multitasking required -- keep it simple), mongrel
(old-
ish and proven), unicorn (simple, reliable, prefork is proven), ebb (C
for
speed, and threads may be more efficient than forking), etc etc.

I don't really see the case for Passenger over these, other than
simplicity of
deployment. Am I missing anything?

Well for one thing, many sites are a mixture of static assets and
dynamic content. It's much more efficient to serve the static assets
from a webserver tuned for serving this sort of content, rather than
serving your entire site from a ruby server.

For another thing, Rails is often still best run non-threaded. This
means you need multiple worker processes. With mongrel/thin/etc this
means running multiple servers bound to different ports, and that in
turn means sticking a proxy of some sort in front, and having the bits
and pieces necessary to start and monitor the required number of
workers, and sorting out things like proxying the SSL variables.

I bought Ezra's Deploying Rails Apps book and built a system by
combining Apache, pen, mongrels, monit and capistrano. It works, but is
complex and a pain to add new apps. With Apache+Passenger it just works
out of the box, is easy to tweak, is far simpler, and you get the REE
memory sharing advantages too.

I don't really see the case for deploying Rack or Rails apps using any
other approach, other than familiarity. Am I missing anything? :)
 
M

Marnen Laibow-Koser

Judson said:
I wanted to amplify with use cases that run more than one app on the
same
server. My experience is that getting two *Rails* apps to play nicely
in
the same environment is a pain. But certainly easier than getting
Mongrel
to run PHP. With Passenger I can run Rails alongside PHP, and serve
static
content far more efficiently.

And running multiple Rails apps with one Passenger installation is
likwise a breeze.

(nginx is on my saw-sharpening list...)

Judson

Best,
 
B

Brian Candler

Marnen said:
And running multiple Rails apps with one Passenger installation is
likwise a breeze.

- although there's some possibility for interaction between them. In
particular, PassengerUseGlobalQueue gives one global queue across all
apps, rather than one queue per application. Also,
PassengerMaxInstancesPerApp can only be set globally rather than per
app.

At least it was like that last time I enquired, but the current
documentation suggests this is still the case.
 
M

Marnen Laibow-Koser

Brian said:
- although there's some possibility for interaction between them. In
particular, PassengerUseGlobalQueue gives one global queue across all
apps, rather than one queue per application. Also,
PassengerMaxInstancesPerApp can only be set globally rather than per
app.

At least it was like that last time I enquired, but the current
documentation suggests this is still the case.

I think it may not be, but don't quote me. :)

Best,
 
N

Nick Dr

=
That sounds tailor-made for Sinatra. However, you should learn something
about
REST, first -- are you sure POST is appropriate?

Ok I tried sinatra. It seems like it fires up webrick on port 4567, so I
take it there's some config file I need to mess with, or my hosting
provider deals with so it'll run on Apache instead?

Also, I can hit my sinatra ruby script from my browser, but when I tried
to hit it from a jQuery AJAX request, I get nothing back and the sinatra
console says that it was an OPTIONS request instead of the GET request
it reports when firefox asks for the page. What am I doing wrong here?
The idea was to jquery post to a ruby script for some JSON data and then
update my canvas based on that data.
FastCGI is obsolete, so scratch that.

The host I was considering, HostingRails, says they'll do a FastCGI
deployment for me. I am (hopefully) expecting pretty high frequency
traffic. Like several hits/min 24/7, but never > 1000 hits per minute,
because this will be a global app available via facebook, so the time
zones should spread it out for me.
Are you sure FastCGI isn't a good option for this?
Passenger and mod_ruby are essentially the same thing, IIRC. But my
understanding is that Passenger works with Rack, which doesn't feel at
all
like CGI. So these might be deployment options, but they have nothing to
do
with how you write and develop your app.

So I can just use the Sinatra lib to route the request, deal with
cookies and sessions, and then hand it to my hosting provider and
they'll set it up properly?

Thanks for all the advice!
 
P

Paul Smith

=

Ok I tried sinatra. It seems like it fires up webrick on port 4567, so I
take it there's some config file I need to mess with, or my hosting
provider deals with so it'll run on Apache instead?

You can use Sinatra with JRuby to host the app via Google AppEngine,
that seems quite elegant. I don't know how AppEngine's pricing
compares to your other hosting offer of course.

http://blog.bigcurl.de/2009/04/running-sinatra-apps-on-google.html
 
N

Nick Dr

Seebs said:
How many hundred thousand hits a day do you have to process?

If the answer is "less than one", you probably don't care much about
speed in practice.

Past that... If you want something more interesting, I am pretty happy
with rails/passenger. Relatively low setup effort and works great, and
while it might be overkill for what you want to do, I really do find
it pretty rewarding.

Well, HOPEFULLY I'm expecting a lot of hits, but these scripts will also
be available via a facebook app, so hopefully the time zones will spread
it out for me, and I'll be getting several hit per minute, 24/7, but
never a lot at once.

That brings up another question I had. Does
FastCGI/Mongrel/Thin/Passenger deal with multithreading for me? Like if
two people request an HTML page I figure it can just serve two copies of
it. But what about scripts? In theory my scripts only take milliseconds
from request to response, but just for arguments sake, if one person
requested it, it started running, hitting the db etc, and then another
person requested it before it was finished, what happens?
 
B

Brian Candler

Ok I tried sinatra. It seems like it fires up webrick on port 4567, so I
take it there's some config file I need to mess with, or my hosting
provider deals with so it'll run on Apache instead?

If you have a Rails hosting provider, they can probably host Sinatra
too. Both just run on top of Rack.

If your hosting provider uses Phusion Passenger (= mod_rails), that can
host Sinatra.
http://www.modrails.com/documentation/Users guide Apache.html#_sinatra

If you have a totally generic hosting provider then you may be stuck
running your app as a cgi-bin or fastcgi (although obviously they'll
still have to provide you with a ruby interpreter). That may be enough
to get you started, but you'd probably be best changing to a different
hosting provider longer term.

I've run small fastcgi apps successfully; experience from many Rails
users has been that it has a tendency to explode. As a result, most ruby
people (and developers) are staying away from fastcgi. But it still
*should* be possible to build rack to work under fastcgi; see the README
in the rack gem. You'll need the ruby fcgi gem, which in turn depends on
the C fcgi library.
Also, I can hit my sinatra ruby script from my browser, but when I tried
to hit it from a jQuery AJAX request, I get nothing back and the sinatra
console says that it was an OPTIONS request instead of the GET request

No idea on that. It all works for me. Use tcpdump to prove or disprove
that jQuery is sending an OPTIONS request; that would show if it's a
problem with your jQuery code.
So I can just use the Sinatra lib to route the request, deal with
cookies and sessions, and then hand it to my hosting provider and
they'll set it up properly?

Depends on how clued up and helpful your hosting provider is :)
if one person
requested it, it started running, hitting the db etc, and then another
person requested it before it was finished, what happens?

Sinatra has a request lock turned on by default, so that the second
request will wait until the first completes, but you can turn it off if
you are sure your application is thread-safe.

However, running under fastcgi or mod_rails, only one request would be
sent at a time to your application. Therefore you will need to spawn
multiple processes to handle concurrent requests. This should be done
for you, but you may wish to tune the parameters for min/max processes
spawned.
 
D

David Masover

David Masover wrote:

Strike the "somewhat".

There's actually some debate about whether or not it can scale. Not something
I'm particularly interested in at the moment, though.
It's written by the same people, and I believe it can take advantage of
some Ruby EE optimizations. But you can use it just as well with MRI
(although I'm not sure why you would -- EE is much faster).

Is there an EE for 1.9 yet? Depending on your app, 1.9.1 may be much faster.
Incredible ease of configuration, EE optimizations. AFAIK, Passenger
has no serious competition on either of these points.

Capistrano is pretty easy, but that's my opinion. But if I use Ruby EE,
Unicorn does the exact same thing, while remaining much more loosely coupled
from the webserver.
Not app deployment so much as configuration.

Configuration is part of deployment. Any serious shop really should have a
task set up for building the entire stack, including the load balancer.
You're missing just about everything. :) Personally, I'm not sure what
the case *against* Passenger is, unless you're using Windows or JRuby.

Complexity. Plus, it used to require Apache...

I suppose a bigger case against it is that it seems like Unicorn can do all of
that, but be far more static-server-agnostic -- I can run it by itself on a
port, or with nginx via a Unix socket.
Didn't 37signals switch to Passenger some time ago?

Yeah, that doesn't really impress me. The important question is why they chose
it -- I linked to an article, not just about Github using nginx+unicorn, but
_why_ they did, and why that looks to me like a good idea.
 
D

David Masover

Right, that's the reason most of the older setups called for something like
Apache or nginx, proxied to something like mongrel.
I wanted to amplify with use cases that run more than one app on the same
server. My experience is that getting two *Rails* apps to play nicely in
the same environment is a pain.

Huh. I don't know that I'd call it "easy", but I was able to solve this by
running those apps as separate user accounts, separate databases and MySQL
passwords, etc. Once I had a task set up for it, the biggest irritation was
managing ports. With Unix sockets and a master/slave setup like Unicorn, that
goes away.
With Passenger I can run Rails alongside PHP, and serve static
content far more efficiently. (nginx is on my saw-sharpening list...)

I definitely ran PHP when I was doing the above. Remember, with the
traditional setup, each mongrel is a separate webserver to proxy to. It's not
hard to proxy to another server running PHP, if you have to.

But basically what I'm hearing is that I'm right -- ease of setup/deployment
is _the_ win for Passenger.

One possible point against passenger: How easy is it to run each individual
Rails app as a separate user?
 
D

David Masover

=


Ok I tried sinatra. It seems like it fires up webrick on port 4567, so I
take it there's some config file I need to mess with, or my hosting
provider deals with so it'll run on Apache instead?

Well, yes and no. Sinatra by default fires up on 4567 using supported servers
(webrick, mongrel, etc). However, it is a Rack app, and you can configure a
rackup file to load your app via anything that does Rack.

So they could use Apache or Nginx (via Passenger), or they could use any of
the standalone Ruby servers behind Apache or Nginx, or they could have some
custom setup. The point is that Rack is the standard modern way of connecting
a webserver to a Ruby web app/framework.
Also, I can hit my sinatra ruby script from my browser, but when I tried
to hit it from a jQuery AJAX request, I get nothing back and the sinatra
console says that it was an OPTIONS request instead of the GET request
it reports when firefox asks for the page.

Quick question: What browser? I had a similar issue with a Chromium build.

One possible test: Run something like netcat locally, so you capture the raw
traffic. I very much doubt Sinatra is wrong -- I bet your browser is
(erroneously) sending OPTIONS instead of GET.
The host I was considering, HostingRails, says they'll do a FastCGI
deployment for me.

Do they also support Rack?
Are you sure FastCGI isn't a good option for this?

No, but I'm sure it's a weird hack, I doubt it really performs well (or people
wouldn't have started using Mongrel in the first place), and I wouldn't trust
a host which _only_ supported FastCGI as an option.

Check that they'll run an arbitrary Rack app.
So I can just use the Sinatra lib to route the request, deal with
cookies and sessions, and then hand it to my hosting provider and
they'll set it up properly?

Hopefully. That's the point of Rack, anyway.
 
M

Marnen Laibow-Koser

David Masover wrote:
[...]
One possible point against passenger: How easy is it to run each
individual
Rails app as a separate user?

Trivial. IIRC, each Passenger app runs as whichever user owns (I think)
it's environment.rb file.

Best,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,709
Latest member
AustinMudi

Latest Threads

Top