Hey all,
Version 0.5.3 (codename Purple Yogurt) of the fastest Ruby server is
out!
Thin is a Ruby web server that glues together 3 of the best Ruby
libraries in web history:
- the Mongrel parser: the root of Mongrel speed and security
- Event Machine: a network I/O library with extremely high
scalability, performance and stability
- Rack: a minimal interface between webservers and Ruby frameworks
Which makes it, with all humility, the most secure, stable, fast and
extensible Ruby web server
bundled in an easy to use gem for your own pleasure.
== What’s new?
Welcome 2 new members to the Thin team (previously composed of me and
me):
Small release for *nix users, but big one of windows users!
- win32 pre-compiled gem now available (send all your love to Kevin
for this one)
- Add prefix option to thin script to mount app under a given path.
If you’re still not sure about trying Thin, here are a couple of
articles:
http://www.deze9.com/jp/blog/post?p=current-uptime-of-the-thin-server-process-behind
*
http://blog.rayngwf.com/2008/01/thin-ruby-web-server-that-is-really.html
== Get it!
sudo gem install thin
Might take some time for the gem mirrors to be updated, try adding
–source http://code.macournoyer.com to the command if it doesn’t work
If you installed a previous alpha version (if you have 0.5.3 already
installed)
uninstall it before: sudo gem uninstall thin
WARNING:
Thin is still alpha software, if you use it on your server you
understand the
risks that are involved.
== Contribute
If you’re using Thin, let me know and I’ll put your site on
http://code.macournoyer.com/thin/users/
Thin is driven by an active community of passionate coders and
benchmarkers. Please join us, contribute
or share some ideas in Thin Google Group:
http://groups.google.com/group/thin-ruby/topics
Also on IRC: thin on freenode
Thanks to all the people who contributed to Thin, EventMachine, Rack
and Mongrel.
Marc-Andre Cournoyer
http://code.macournoyer.com/thin/
This has been working so well on my Mac dev machine, I built it out on
my RHEL server and started it with:
thin start -e production -p -d
This is dropping it in where a mongrel was. Listening on a high number
port.
I can go to http://rootdomain: and there’s my site.
However, I can’t get to it using Apache’s mod_proxy.
Killing the thin process and restarting the mongrel verifies that the
proxy is set up right.
Any thoughts?
Thx
someone reported that the --user and --group options are not working :
http://groups.google.com/group/thin-ruby/browse_thread/thread/a2483855a3d3380e/d796bf39b2b32d17
maybe you’re experiencing the same issue. Can you check on w/ user is
the thin process running?
On 18-Jan-08, at 10:15 PM, s.ross wrote:
I can go to http://rootdomain: and there’s my site.
However, I can’t get to it using Apache’s mod_proxy.
Any luck with restarting or stop/start of apache?
With OS X 10.5 I’m doing that a lot now, never in 10.4 – if anyone
knows what that’s all about, do tell.
Cheers,
Bob
Bob H. – tumblelog at
http://www.recursive.ca/so/
Recursive Design Inc. – weblog at
http://www.recursive.ca/hutch
http://www.recursive.ca/ – works on
http://www.raconteur.info/cms-for-static-content/home/
Thin runs in a single thread, no need for a mutex there.
Got it up and running … for a while. It’s running as root/root and
I’m not certain why it was not responding to proxied requests, but
I’ll have to track that down later. Here’s the puzzler for right now.
I decided to use the sitealizer Rails plugin for this site and it
contains code such as:
def store_visits
begin
mutex = Mutex.new
mutex.lock
$visits.each do |env|
SiteTracker.create(
:user_agent => env['HTTP_USER_AGENT'],
:language => env['HTTP_ACCEPT_LANGUAGE'],
:path => env['PATH_INFO'],
:ip => env['REMOTE_ADDR'],
:referer => env['HTTP_REFERER']
)
end
open(File.dirname(__FILE__)+'/last_update','w'){|f| f.puts
Time.now.to_s}
mutex.unlock
rescue => e
RAILS_ENV == ‘production’ ? logger.info(e) : logger.debug(e)
ensure
mutex.unlock
end
end
This causes thin to crash as follows:
ThreadError (not owner):
/vendor/plugins/sitealizer/lib/sitealizer.rb:80:in unlock' /vendor/plugins/sitealizer/lib/sitealizer.rb:51:in
join’
/vendor/plugins/sitealizer/lib/sitealizer.rb:51:in use_sitealizer' /vendor/rails/actionpack/lib/action_controller/filters.rb:456:in
send’
/vendor/rails/actionpack/lib/action_controller/filters.rb:456:in
call' /vendor/rails/actionpack/lib/action_controller/filters.rb:435:in
call’
/vendor/rails/actionpack/lib/action_controller/filters.rb:637:in
call_filter' /vendor/rails/actionpack/lib/action_controller/filters.rb:619:in
perform_action_without_benchmark’
/vendor/rails/actionpack/lib/action_controller/benchmarking.rb:
66:in perform_action_without_rescue' /usr/local/lib/ruby/1.8/benchmark.rb:293:in
measure’
/vendor/rails/actionpack/lib/action_controller/benchmarking.rb:
66:in perform_action_without_rescue' /vendor/rails/actionpack/lib/action_controller/rescue.rb:125:in
perform_action’
/vendor/rails/actionpack/lib/action_controller/base.rb:473:in
send' /vendor/rails/actionpack/lib/action_controller/base.rb:473:in
process_without_filters’
/vendor/rails/actionpack/lib/action_controller/filters.rb:624:in
process_without_session_management_support' /vendor/rails/actionpack/lib/action_controller/ session_management.rb:114:in
sass_old_process’
/vendor/plugins/haml/lib/sass/plugin.rb:116:in process' /vendor/rails/actionpack/lib/action_controller/base.rb:326:in
process’
/vendor/rails/railties/lib/dispatcher.rb:39:in dispatch' /usr/local/lib/ruby/gems/1.8/gems/thin-0.5.3/lib/rack/adapter/ rails.rb:52:in
serve_rails’
/usr/local/lib/ruby/gems/1.8/gems/thin-0.5.3/lib/rack/adapter/
rails.rb:67:in call' /usr/local/lib/ruby/gems/1.8/gems/thin-0.5.3/lib/thin/ connection.rb:30:in
process’
/usr/local/lib/ruby/gems/1.8/gems/thin-0.5.3/lib/thin/
connection.rb:16:in receive_data' /usr/local/lib/ruby/gems/1.8/gems/eventmachine-0.10.0/lib/ eventmachine.rb:1056:in
event_callback’
/usr/local/lib/ruby/gems/1.8/gems/eventmachine-0.10.0/lib/
eventmachine.rb:224:in run_machine' /usr/local/lib/ruby/gems/1.8/gems/eventmachine-0.10.0/lib/ eventmachine.rb:224:in
run’
/usr/local/lib/ruby/gems/1.8/gems/thin-0.5.3/lib/thin/server.rb:
55:in listen!' /usr/local/lib/ruby/gems/1.8/gems/thin-0.5.3/lib/thin/server.rb: 44:in
start!’
/usr/local/lib/ruby/gems/1.8/gems/thin-0.5.3/bin/thin:85:in start' /usr/local/lib/ruby/gems/1.8/gems/thin-0.5.3/bin/thin:116:in
send’
/usr/local/lib/ruby/gems/1.8/gems/thin-0.5.3/bin/thin:116
/usr/local/bin/thin:19:in `load’
/usr/local/bin/thin:19
Any thoughts?
Thanks
And even if it would be multi threaded it won’t work. Every time
store_visits methods is executed new mutex is created, so there won’t
be synchronization.
Thin runs in a single thread, no need for a mutex there.
:referer => env['HTTP_REFERER']
end
–
Rados³aw Bu³at
http://radarek.jogger.pl - mój blog
And even if it would be multi threaded it won’t work. Every time
store_visits methods is executed new mutex is created, so there won’t
be synchronization.
The reason for error message "ThreadError (not owner):
/vendor/plugins/sitealizer/lib/sitealizer.rb:80:in `unlock’
(…)
"
is that you call ‘unlock’ method twice. ‘ensure’ block is ok, so
remove previous calling (a the end of begin block).
–
Rados³aw Bu³at
http://radarek.jogger.pl - mój blog
Oooooh, you’re right. Unlock is called twice. This is code in a Rails
plugin, and I know that’s no disclaimer of responsibility for its
working right. I still have to take responsibility for that. I’ll let
the author know, but here’s a follow-on question.
Assuming bad behavior on the part of the client code (in this case,
calling unlock twice), should this be rescued, the error logged, and
an attempt made to keep the server alive or should the process
terminate (as it currently does)?
I believe the intent was well-intentioned but that it doesn’t prevent
concurrency issues cross-process and obviously provides no benefits in
a Rails process because Rails puts a great big mutex around the whole
request/response pipeline.
Thanks for looking into this.
–steve
Of course it depends on specific situation but in about 99% situations
you should log error and give message to user describing what was
wrong (it could be even well known rails message “something went
wrong” ;)). Of course there exceptions that you should explicitly
rescue and exceptions that are very generic to catch every time.
For example, when I implement authentication I do:
def signin
user = User.authenticate(params[:login], params[:password])
#(…)
rescue User::AuthenticationException
flash[:error] = “error message”
end
But of course I can make mistake somewhere and for example I could get
exception because I call method on nil object (NoMethodError
exception). In this situation you can use rails handling exceptions
mechanism (Ryan B. to the rescue -
#53 Handling Exceptions - RailsCasts).
So for global handling you can write:
def rescue_action(exception)
case exception
when NoMethodError
render :text => “ups…”
else
super
end
end
–
Rados³aw Bu³at
http://radarek.jogger.pl - mój blog
I have a rescue_exception function but this problem is happening in a
place where it kills off the server. It doesn’t do the same with
mongrel and I’m not sure why.
Which server do you use? Maybe it doesn’t handle all kind of
exceptions (in this case ThreadError)?
–
Rados³aw Bu³at
http://radarek.jogger.pl - mój blog
On Jan 19, 2008, at 10:46 AM, Radosław Bułat wrote:
Of course it depends on specific situation but in about 99% situations
you should log error and give message to user describing what was
wrong (it could be even well known rails message “something went
wrong” ;)). Of course there exceptions that you should explicitly
rescue and exceptions that are very generic to catch every time.
I have a rescue_exception function but this problem is happening in a
place where it kills off the server. It doesn’t do the same with
mongrel and I’m not sure why.
–steve
On Jan 19, 2008, at 11:32 AM, Radosław Bułat wrote:
I have a rescue_exception function but this problem is happening in a
place where it kills off the server. It doesn’t do the same with
mongrel and I’m not sure why.
Which server do you use? Maybe it doesn’t handle all kind of
exceptions (in this case ThreadError)?
You were exactly right about the problem being that the mutex was
unlocked twice. I have the site running now (in production mode on my
production server ) and it seems just fine.
The biggest difference between mongrel and thin in this instance was
that the double unlock killed thin, while mongrel continued on through
the error.
thanks
On Jan 19, 2008, at 11:32 AM, Radosław Bułat wrote:
Which server do you use? Maybe it doesn’t handle all kind of
exceptions (in this case ThreadError)?
Typically, I use Apache proxied to mongrel. It, evidently, does gobble
up ThreadError. This was a proof of concept for Apache proxied to
Thin. It does not behave the same in identical circumstances on the
same machine (same port, environment, etc.).
hey steve,
I tried reproducing your error causing Thin to crash. I was able to
reproduce the error, unlocking a mutex twice, but the ThreadError was
properly caught by Thin rescue block.
If you can help me reproduce this please add any details to
http://thin.lighthouseapp.com/projects/7212/tickets/1-uncaught-threaderror
thx,
Marc