slow rails stack - ruby-on-rails

When I run
rails server
or
rake -T
or some other rails script, it takes a lot of time, approx 1 minute.
What is the best way to determine what exactly is so slow ?
How can the speed be improved ?
Rails v is 3.0.3 run trough ruby 1.9.2 (RVM) - Linux

That is bothering me also, since I have switched to Rails 3.
To your second question: I found by digging through the framework that the initializers take about half the time of a simple rake or rails call before it actually starts doing its task.
If you put these simple timing lines into the loop of initializer calls in $GEM_PATH/gems/railties-3.0.3/lib/rails/initializable.rb (or piggy-back it if you like):
def run_initializers(*args)
return if instance_variable_defined?(:#ran)
t0 = Time.now
initializers.tsort.each do |initializer|
t = Time.now
initializer.run(*args)
puts("%60s: %.3f sec" % [initializer.name, Time.now - t])
end
puts "%60s: %.3f sec" % ["for all", Time.now - t0]
#ran = true
end
EDIT: Or, for railties 4.2.1:
def run_initializers(group=:default, *args)
return if instance_variable_defined?(:#ran)
t0 = Time.now
initializers.tsort.each do |initializer|
t = Time.now
initializer.run(*args) if initializer.belongs_to?(group)
puts("%60s: %.3f sec" % [initializer.name, Time.now - t])
end
puts "%60s: %.3f sec" % ["for all", Time.now - t0]
#ran = true
end
... you can follow up what happens. On my system, which is a 2.4 Core 2 Duo MacBook the initializers take about 7 seconds.
There are a few that are especially slow on my system. When I filter all out below a second, I get this result on my system:
load_active_support: 1.123 sec
active_support.initialize_time_zone: 1.579 sec
load_init_rb: 1.118 sec
set_routes_reloader: 1.291 sec
I am sure somebody (is it me?) will take some time to start there and optimize.

Our Rails 3.1 startup time was almost 1 minute (having a lot of gems)
Then we found out about some Ruby 1.9.3 tuning options on reddit:
http://www.reddit.com/r/ruby/comments/wgtqj/how_i_spend_my_time_building_rails_apps/c5daer4
export RUBY_HEAP_MIN_SLOTS=800000
export RUBY_HEAP_FREE_MIN=100000
export RUBY_HEAP_SLOTS_INCREMENT=300000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
export RUBY_GC_MALLOC_LIMIT=79000000
put this in your shell environment/profile/bashrc, and you are done.
We boosted our startup from 1 minute to 9 seconds

One workaround I use for this is to preload the rails environment with rails-sh. That way only the first rails/rake command is slow and the rest are pretty fast. Wrote a fuller answer to it in this question.
Another way I tried more recently and is compatible with the first is installing a patched ruby (with rvm or rubyenv or from source) and adjusting environment variables (see #stwienert's answer). The falcon patch and railsexpress patches both seem to pick up significant performance in ruby 1.9. Check out rvm/rubyenv on how to install patched rubies with them.

I used robokopp's tip here to discover that most of the time was being used in the build_middleware_stack and load_config_initializers steps for me. This is because I am using the omniauth gem that adds middlewares and perhaps has heavy initialization steps. I am on Rails 3.1.rc1, and my initialization takes almost 13 seconds (I am on ruby 1.9.2p180).
Even for brand new rails 3.1.rc1 app, the initialization takes ~3.6 seconds, with max time taken by load_config_initializers.
So I suggest you look for gems/your own code that have heavy initializers or add too many middlewares.

Related

Sidekiq / Ruby On Rails - Lock using Redis (Redlock) not locking correctly

I'm trying to lock a part of my code using Redis, with Redlock library.
I've implemented it here:
def perform(task_id, task_type)
lock_manager = Redlock::Client.new([ "redis://127.0.0.1:6379" ])
lock_key = "task_runnuer_job_#{task_type}_#{task_id}"
puts("locking! #{task_id}")
lock_task = lock_manager.lock(lock_key , 6 * 60 * 1000)
if lock_task.present?
begin
# Exec task...
Services::ExecTasks::Run.call task.id
ensure
puts("unlocking! #{task_id}")
lock_manager.unlock(lock_task)
end
else
puts("Resource is locked! #{lock_key}")
end
end
What I get when running multiple Sidekiq jobs at the same time, is the following logs:
"locking! 520"
"locking! 520"
"unlocking! 520"
"unlocking! 520"
This happens when both of my 520 task, which should not be executed together, are being called with 1ms diffrence.
Yet sometimes the lock works as expected.
I've checked Redis and it works just fine.
Any ideas? Thanks!

How to run a cron job every 10 seconds in ruby on rails

I am trying to run a cron job in every 10 seconds that runs a piece of code. I have used an approach which requires running a code and making it sleep for 10 seconds, but it seems to make drastically degrading the app performance. I am using whenever gem, which run every minute and sleeps for 10 seconds. How can I achieve the same w/o using sleep method. Following is my code.
every 1.minute do
runner "DailyNotificationChecker.send_notifications"
end
class DailyNotificationChecker
def self.send_notifications
puts "Triggered send_notifications"
expiry_time = Time.now + 57
while (Time.now < expiry_time)
if RUN_SCHEDULER == "true" || RUN_SCHEDULER == true
process_notes
end
sleep 10 #seconds
end
def self.process_notes
notes = nil
time = Benchmark.measure do
Note.uncached do
notes = Note.where(status: false)
notes.update_all(status: true)
end
end
puts "time #{time}"
end
end
Objective of my code is to change the boolean status of objects to true which gets checked every 10 seconds. This table has 2 million records.
I suggest using a Sidekiq background jobs for this. With the sidekiq-scheduler gem you can run ordinary sidekiq jobs schedules in whatever internal you need. Bonus points for having a web-interface to handle and monitor the jobs via the Sidekiq gem.
You would use the clockwork gem. It runs in a separate process. The configuration is pretty simple.
require 'clockwork'
include Clockwork
every(10.seconds, 'frequent.job') { DailyNotificationChecker.process_notes }

Jruby (1.7.5) + MSSQL-2012 + torquebox 2.2.0 DB issue

I have Jruby on rails Jruby (1.7.5) + MSSQL-2012 + torquebox 2.2.0 + Rails-2.3.18. The application got connected to the database without any problem.
I am installed active-recorder-jdbc (1.2.8) * active-record-mssql-jdbc (2.8.1)
The issue is If i made any DB hit even to fetch Single row . It would take to finish the request around Completed in 938504ms (View: 4, DB: 938497) | 200 OK The request took nearly 15 min to complete .
But in the front end UI . I got the apache Timeout error . How can i detect the problem and fix this.
I took the Thread dump and all. It shows like below
parking to wait for <0x00000000fc85dbe8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:894)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
at org.jruby.RubyThread.lockInterruptibly(RubyThread.java:1461)
at org.jruby.ext.thread.Mutex.lock(Mutex.java:91)
at org.jruby.ext.thread.Mutex.synchronize(Mutex.java:147)
at org.jruby.ext.thread.Mutex$INVOKER$i$0$0$synchronize.call(Mutex$INVOKER$i$0$0$synchronize.gen)
at org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:143)
at org.jruby.runtime.callsite.CachingCallSite.callIter(CachingCallSite.java:154)
at org.jruby.ast.CallNoArgBlockNode.interpret(CallNoArgBlockNode.java:64)
at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
seems like there might be a dead-lock or more likely some heavy contention (on newer JRuby 1.7.x you might see more useful traces in the dump) ... esp. AR's pool in 2.3 is not performing well concurrently. consider back-porting the pool from a newer versions, also be aware if using AR sessions that there's a nasty bug with the pool and the session-store being involved.

How to identify slowness lines in Rails app?

I have a Rails app running on 4.1.6 and Ruby 2.1.3. Some times on some requests they take so long, but it doesn't happen all the times. When I check newrelic I still can't identify or trace the slowness lines.
check out perftools - you can use googles perftools, or the ruby specific implementation. There's a nice write-up about it here
It runs through your application and finds bottlenecks by determining time spent in individual method calls. You'll get output like this:
Total: 23 samples
18 78.3% 78.3% 18 78.3% BigDecimal#div
4 17.4% 95.7% 4 17.4% BigDecimal#*
1 4.3% 100.0% 23 100.0% BigMath#PI
0 0.0% 100.0% 23 100.0% BigMath.PI
In this case, you'd need to spend some time looking at the div method in BigDecimal
It may be a slow API call.
Here is the code for Doorkeeper::TokensController#create
module Doorkeeper
class TokensController < Doorkeeper::ApplicationMetalController
def create
response = strategy.authorize
self.headers.merge! response.headers
self.response_body = response.body.to_json
self.status = response.status
rescue Errors::DoorkeeperError => e
handle_token_exception e
end
# ...snip...
private
def strategy
#strategy ||= server.token_request params[:grant_type]
end
end
end
I don't see any heavy lifting done in here.
Read this New Relic blog post about adding custom metrics to your code. This will replace "Application code" entries in your trace with greater detail about what is going on inside your code.
I cannot copy the linked information here due to copyright.

Net-ssh timeout for execution?

In my application I want to terminate the exec! command of my SSH connection after a specified amount of time.
I found the :timeout for the Net::SSH.start command but following the documentation this is only for the initial connection. Is there something equivalent for the exec command?
My first guess would be not using exec! as this will wait until the command is finished but using exec and surround the call with a loop that checks the execution status with every iteration and fails after the given amount of time.
Something like this, if I understood the documentation correctly:
server = NET::SSH.start(...)
server.exec("some command")
start_time = Time.now
terminate_calculation = false
trap("TIME") { terminate_calculation = ((Time.now - start_time) > 60) }
ssh.loop(0.1) { not terminate_calculation }
However this seems dirty to me. I expect something like server.exec("some command" { :timeout=>60}). Maybe there is some built in function for achieving this functionality?
I am not sure if this would actually work in a SSH context but Ruby itself has a timeout method:
server = NET::SSH.start ...
timeout 60 do
server.exec! "some command"
end
This would raise Timeout::Error after 60 seconds. Check out the docs.
I don't think there's a native way to do it in net/ssh. See the code, there's no additional parameter for that option.
One way would be to handle timeouts in the command you call - see this answer on Unix & Linux SE.
I think your way is better, as you don't introduce external dependencies in the systems you connect to.
Another solution is to set ConnectTimeout option in OpenSSH configuration files (~/.ssh/config, /etc/ssh_config, ...)
Check more info in
https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/config.rb
what I did is have a thread that's doing the event handling. Then I loop for a defined number of seconds until channel closed.If after these seconds pass, the channel is still open, then close it and continue execution.

Resources