Configuring Rails: Thin + Nginx

Passenger era

Few years ago, we were using Apache and Phusion Passenger and had no issues that we have in FastCGI era :). But usage of Phusion Passenger has become memory consuming. Each request creates a thread and there is only way to handle this - that is to limit number of threads per application. But consider situation when you have limit for 2 threads per application, and 2 users with slow connection request site. What happens in this situation? Right, other users are blocked until at least one request is finished. Having 10 applications on single Apache server causes full memory usage and denial of service. Our tuning has become a headache. So, we have decided to use different architecture.

Thin + Nginx

Historically we decided to use Thin, because it was a trend at that time. Mongrel was outdated and Unicorn was not popular (or maybe not available at that time). Thin is single threaded but based on eventmachine library, thus it can accept thousands of requests without denial of service, just replying as soon as its single thread becomes available for processing next request.
Nginx was selected because it is lightweight. We didn't want to install such monster as Apache just for static files handling. This way, we selected Nginx as reverse proxy and asset server. Thin was selected for rails application processing. Let's see how it's easily configured.

Thin Configuration

That is pretty clear and close to default thin configuration:

As you can see Thin is configured to handle 512 connections simultaneously by default. If you want to have Thin cluster with 2 servers, you need to add some more lines:

servers: Number of servers in cluster. Each next server port will be incremented by 1 from previous. For current configuration it will use ports 3000 and 3001
onebyone
: restart servers one by one (ensure that at least one server is handling requests)
wait: maximum waiting time for server to be started in seconds

So, lets start our Thin:
thin start -C thin.yml

That is all. Now our rails application is available on localhost:3000 and localhost:3001. It works fast, but as soon as Thin is single threaded, we need to add nginx to handle static files. Otherwise, if application has images, client browser will download each image one by one and it will take a lot of time.

Nginx configuration

Basic nginx configuration is pretty simple and we used almost default one except servers section.

The only thing that is not default is gzip compression. If you have a lot of HTML, CSS and Javascripts you will find this option useful.

And now lets configure our site. We configured our nginx to load configurations from sites-enabled folder: include /etc/nginx/sites-enabled/*. Let’s create file named vertaline here (your site name in your case). Here is configuration:

Firstly, we have configured our cluster. It consists of 2 servers. Requests are splitted by ip addresses between them.

Next, we have configuration of server name, site root (should go to rails public folder, not rails root) and logs.

At the location section, we have proxy parameters and directives in order to set expiration headers for existing files and to pass requests to our cluster (for handling with rails routes) if the files are missing.

Last section contains mapping of status errors to static status pages. You can customize these pages for your application by replacing default html pages in public directory.

Ruby on Rails Guides provides recommendations for making location section for assets and turning on static gzip compression for rails 3.1. But you need to configure nginx module.

This option is very useful, because Rails 3.1 assets pipeline makes static gzipped files for your css and javascripts by using assets:precompile task.

Conclusion

That time when rails applications were slow, unresponsive and heavily configured in production environment has ended. As you can see, current configuration is simple even for newbies. Also, after application update there are no more unknown errors, you can test your application behavior just running it on your local machine with production environment and you will get same behavior on live server. Rails has always been very fast in development and now it becomes quite competitive in production speed. As Rails developer, I like this tendency. Programming should be fun. So have fun with rails development.

 

Chaining in Ruby on Rails

Sometimes you need to select obejcts from related table.

Suppose you have User, Assignments and Tasks.

Users have assignments to different tasks with different roles.

Example:

And you need to select open tasks for current user on active "developer" role.

So,you can select user assignments that are active on developer role:

And you can select user opened tasks:

But how to select both?

The standard approach can be used and we select by:

But using this way, you should convert your scopes to arel statements.

It would be good when we can merge those scopes.

And rails already have this possibility. So, rewriting this code we will get:

Quite simple.