passenger standalone with god on rvm

March 21st, 2011 3 comments

Some time ago I have migrated my server to nginx. Now I got first chance to setup rails application on it.

Searching for new experiences I have tried a new setup – passenger standalone on rvm monitored by god and cron  (see Q&A on the end).

Prerequisite to that guide is a working deployment script (putting files on server and db:migration working also rvm set up on server). Important is also to replace all occurrences of “/path/to/application” with your real path to application on server.

Nginx is also required, in case you do not have it already you can install it with following command (ubuntu server on linode):

sudo apt-get install nginx

Assuming you have an deploy script up and running you need to add few changes before deployment.

First add god configuration, in your RAILS_ROOT create file config/local.god:

passenger_config = {
:instances => (1..3),
:path => '/path/to/your/application/current'
}
God.watch do |w|
w.name = 'Passenger'
w.start = "ps -U $USER u | grep -v awk | awk '/nginx/ {print $2}' | xargs kill 2>/dev/null ;
passenger start #{passenger_config[:path]} -d  -e production \
-S #{passenger_config[:path]}/tmp/pids/passenger.socket --pid-file #{passenger_config[:path]}/tmp/pids/passenger.pid \
--min-instances #{passenger_config[:instances].min} --max-pool-size #{passenger_config[:instances].max}"
w.stop = "passenger stop #{passenger_config[:path]} --pid-file #{passenger_config[:path]}/tmp/pids/passenger.pid"
w.pid_file = "#{passenger_config[:path]}/tmp/pids/passenger.pid"
w.behavior(:clean_pid_file)

w.start_if do |start|
start.condition(:process_running) do |c|
c.interval = 5.seconds
c.running = false
end
end

end

Also new gems have to be added in Gemfile:

group :production do
gem 'passenger', '~>3.0.5'
gem 'god', '~>0.11.0'
end

Now deploy both files to server, they will be needed later on, and do not forget to run

bundle install --without=production

before deployment.

Second add an request to restart passenger after deploy:

touch /path/to/application/tmp/restart.txt

If your deployment script is capistrano you should use the following snippet:

namespace :deploy do
[:start, :stop].each do |method|
task method, :roles => :app, :except => { :no_release => true } do
run "local_god #{method} Passenger"
end
end
task :restart, :roles => :app, :except => { :no_release => true } do
run "touch #{File.join(current_path,'tmp','restart.txt')}"
end
end

So now lets go to server to finish configuration.

We need to install god and passenger (which we added on the beginning):

bundle install --without=development test cucumber

please note that cucumber is only required when you use it, skip this param if cucumber is only an tasty vegetable for you.

One of most important steps is to create god wrapper that will be used for starting application (replace my_ruby_1.9.2@my_application with your rvm identifier):

rvm wrapper my_ruby_1.9.2@my_application local god

Next we need to make test run of passenger, it will also compile nginx and notify of any problems if it finds any:

cd /path/to/application/current ; passenger start

Passenger will be started on port 3000 if there is no firewall on server (you missed to install it) then you can visit your browser and enter your server.address:3000. adding -p 8080 would server application on the port 8080 (welcome java users). To stop passenger just hit CTRL+C :)

When that works we can set up proxy in the main nginx configuration. On ubuntu (linode) the steps look as follows:

sudo vim /etc/nginx/available-sites/your-application.conf

and put the following content (do not forget to replace my_domain with your dns name of the server):

server {
listen   80;
server_name  my_domain;

access_log  /var/log/nginx/my_domain.access.log;
error_log  /var/log/nginx/my_domain.error.log;

location / {
proxy_pass        http://unix:/path/to/application/current/tmp/pids/passenger.socket;
proxy_set_header  X-Real-IP  $remote_addr;
}
}

after that (ESC :wq) you need to link configuration and restart server

sudo ln -s /etc/nginx/sites-available/your-application.conf /etc/nginx/sites-enabled/your-application.conf
sudo /etc/init.d/nginx restart

last step is to put local god into autorecovery mode with a simple cron job run crontab -e and enter the following content:

* * * * * ps aux | grep -v grep | grep -q "local\.god" || /home/user_name/.rvm/bin/books_god -c /path/to/application/current/config/local.god

That’s all, in one minute your server should be ready, do not forget that first call to passenger application might be sluggish, but it is only the first one when rails need to be initialized, rest of them is really fast.

To check the whole setup you could put small change in some view, deploy application, refresh your browsers (wait few seconds for rails startup) and check your results.

Q & A

Q: Why passenger, why not unicorn or thin ?

A: It is extremely easy to set up.

A: It is one of the fastest ruby servers (some say it is fastest one).

A: It takes far less memory then glassfish or torquebox.

Q: Why passenger standalone, not integrated into apache or nginx ?

A: It is integrated with nginx, but installation is automated – almost no manual steps needed.

A: It runs from user context, so it can be fully controled by user and does not affect other users.

A: It does not need to recompile main server – no dependencies for serving other pages, multiple version can be run at the same time.

Q: Why rvm?

A: It allows easy maintenance of ruby version for user installations.

A: It allows to separate gem repositories for multiple applications.

Q: Why God ?

A: It allows easy monitoring and management of processes – in our case manage passenger standalone.

Q: Why Capistrano ?

A: Really?

Q: Why do you kill nginx when starting passanger ?

A: It’s a hack, it might sometimes happen that passenger process is already stopped but nginx did not finished it’s operation yet, so to allow new process to start we kill the old one.

Q: Can I ask a new question, or provide more answers

A: I encourage you to ask questions and give answers, of course I will post only those that give any value.

fastest way to get git server v2

March 19th, 2011 1 comment

Over a year ago I have posted instruction how to setup simple git server, today I had to do it again but already having code so here is new instruction.

Create remote repository:

ssh mpapis@niczsoft.com -C "git init --bare repos/library3.git"

Create local repository:

git init
git add .
git commit -m "initial commit"

Tell local repository to synchronize with remote repository:

git remote add origin mpapis@niczsoft.com:repos/library3.git
git config branch.master.remote origin
git config branch.master.merge refs/heads/master
git push

You might be interested in the original post: fastest way to get git server

Categories: Development, Hosting, Linux Tags:

linux server memory management

February 27th, 2011 Comments off

It has been long time since last post, but finally something useful shown up, today I want to present simple script for monitoring memory in Linux.

But first happy news: our server is now sucessfully migrated to nginx, no more apache, now maximal memory usage is 20MB per process.

So here is script, it is almost simple, find some processes, and kill them if to much RAM used:

#!/bin/bash

threshold_mb=25
kill_at_mb=$((threshold_mb*5))
memory=$(free -m | awk '{if (FNR==2) print $2}')
threshold=$((threshold_mb*100/memory))
kill_at=$((kill_at_mb*100/memory))
log=/dev/shm/psaux.log
count=$(ps aux | awk -v threshold=$threshold '{if (FNR==1 || $4>=threshold) print}' | tee $log | wc -l)
[ $count -gt 1 ] && echo "Showing processes over ${threshold_mb}MB, killing processes over ${kill_at_mb}MB" && cat $log

cat $log | awk -v kill_at=$kill_at '{if ($4>kill_at) print $2" "$4 }' | while read pid mem;
do
used_mb=$(($(echo $mem | sed 's/\.//')*memory/1000))
# fix rounding problem in awk
if [ $used_mb -gt $kill_at_mb ]; then
kill -9 $pid
echo "pid $pid used ${used_mb}MB - killed"
fi
done
rm -f $log

Most important in this script are first two variables, threshold_mb which is a limit for showing processes (it is rough comparison) and kill_at_mb which is limit for killing processes, by default this limit is 5 times bigger then showing threshold. Cause killing is more important operation additional check for used memory is more strict to be sure, only processes over the limit are killed.

Save it to disk and in crontab:

sudo crontab -e

add the following lines:

MAILTO=<your @email>
* * * * * /root/bin/psaux.sh

That’s all, now add some filter in your mailbox to ignore mails form server – this is all automatic, but you might want to have this for later check if some important processes are missing.

clean linux tmp

November 2nd, 2010 Comments off

Doing some security check on my laptop I found that some files are kept on disk even I do not want to – /tmp directory.

Temp is kind of places in system that should not be kept on encrypted partition, so I have decided to use tmpfs.

First define an fstab entry to keep /tmp on tmpfs:

tmpfs                /tmp                 tmpfs      rw,mode=1777          0 0

Clean all data and mount it:

rm -rf /tmp/*
mount /tmp

Now your data is kept only till yours computer is restarted.

But wait it keeps growing, I restart my laptop once few months, what then ?

No problem a handy script might be useful, save it as /root/bin/clean_tmp.sh

#!/bin/bash

diff <( lsof +D /tmp/ | awk '{print $9}' | grep -v '^NAME$' )  / {print $2}' | grep -ve '\.X' | xargs rm -fv

What it does ? – remove all files older then 60 minutes and not used by any application.

Now connect script in root cron:

5 * * * * /root/bin/clean_tmp.sh

Now your temp is secure and clean.

You will get list of removed files on your local mail account, to prevent this email remove just “v” from “xargs rm -fv” from the script.

Categories: Linux Tags: , , , , , , ,

jquery pure templates

November 1st, 2010 2 comments

This story will be about jquery pure templates.

During developing new project I found great library Pure by beebole and I was going to write about it in first place. but with time when using it I found more and more issues with it. My first idea was to fix it, and I started doing that, but in the middle of debugging I found out it’s not that easy, 20KB of sources is hard to change.

So I have decided to write my own code, using very similar idea but different approach. My library is still pure, does not require putting fancy markers into html in manner to fill it with data, it is enough to write code which can be matched by jquery. My first try was with putting selectors directly into data description like:

data = {'a#my':"my url",'a#my@href':"#/url"}

After I got proof of concept in only 3 hours of coding I thought it would be good to allow mapping any keys to a map of selectors, so it is no more required to return selectors as keys of JSON:

data2 = {'name':"my url",'link':"#/url"}

using simple map file:

map2 = {'name':'a#my','link':'a#my@href'}

So how to call it ? Simple :) just include lib in the header:

<script src="jquery-pure-template.js" type="text/javascript"
        charset="utf-8"></script>

And call render on jquery matching elements:

$('.user').render(data);

or using map file:

$('.user').render(data2,map2);

Thats all needs this html:

<div class="user"><a href="#"></a></div>

and finally you will get as output this html:

<div class="user"><a href="#/url">my url</a></div>

This was simple example, but it will also work with arrays, and nested arrays too, just give it a chance, and keep in mind don’t force html to change the flow, try to make data keep the flow, not view.

Ofcourse there might be certain problems with performance with the chosen approach, first of all performance. Arrays over 500 elements tend to perform quite bad, but using nesting arrays can hold up to 5000 elements without big problem on decent computer. Additionally putting id’s into collection should additionally give some 20% speed up in finding elements by jquery.

I know there are faster solutions, that can probably render lots of data, but mine is simple, only 100 lines now (70 in first version), this makes it extremely easy to maintain and change, hawing less code is better then more :)

This post is also available in Polish version.
Software described here is a plugin for jquery.

Get Adobe Flash playerPlugin by wpburn.com wordpress themes