Scale up as you grow — whether you're running one virtual machine or ten thousand.

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.

This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Nice article, but actually i don’t think is correct to speak about “memory leaks”. 99.99 out of 100 the problem is a “normal” memory bloating: Ruby GC allocate some more memory and the tipical linux malloc implementation will not release it.
Some related reading: https://blog.engineyard.com/2009/thats-not-a-memory-leak-its-bloat http://stackoverflow.com/questions/2215259/will-malloc-implementations-return-free-ed-memory-back-to-the-system
You’ll also want to use Unicorn’s out of band garbage collection.
require ‘unicorn/oob_gc’ use Unicorn::OobGC, 5
That will force Unicorn to GC after every 5th request before it does any more processing.
You don’t need to (and shouldn’t) disconnect from DB and Redis in before_fork.
Also, unicorn-worker-killer is great but it’s not enough - also there are chances that a single request bloats a tremendous amount of memory, and you don’t want the OOM killer to aim at PostgreSQL or sshd. My favorite is to tweak oom_adj to tell the kernel that it should kill those workers first before anything.
So your after_fork will look like this:
after_fork do |server, worker| ActiveRecord::Base.establish_connection Resque.redis.client.reconnect File.write “/proc/#{Process.pid}/oom_adj”, ‘12’ end
Hope this helps.
Can you elaborate on why “You don’t need to (and shouldn’t) disconnect from DB and Redis in before_fork.”?
re: no need to disconnect from DB and Redis in before_fork
By disconnecting in before_fork, you are closing the connection at the parent process every time you spawn a child, which is only needed once - you’re beating a dead horse. Connection handling is a child’s concern (after_fork) rather than a parent’s concern (before_fork).
ActiveRecord’s connection pool is now keyed by Process.pid, so it’s always safe to call ActiveRecord::Base.establish_connection in after_fork - the connection will never be shared with the parent, no need to disconnect at the master anyway.
On Unicorn, the master process is a singleton and can be used in many ways - spawn a thread and run EventMachine loop inside it to run scheduled / background jobs, etc. And there it’s useful to keep the AR connection open. Only main thread will be inherited to a child (on linux systems at least) so it’s safe to have threads.
Very interresting post mate. Can u explain one thign though about the license of unicorn-worker-killer: can i use it in my comercial application without being oblidged to open source my app?
much appreciated,
Personally I just run a cron command every few minutes that cycles through restarting each worker:
pkill -QUIT -of ‘unicorn_rails worker’
here is a rolling restart configuration: https://github.com/coletivoEITA/noosfero-cookbook/blob/master/templates/default/unicorn.conf.rb.erb
Another gotcha with preload_app true: if your deployment scripts do a restart with sig HUP, it will no longer reload application code. You must do an upgrade with sig USR2 and QUIT.
Good article.
Unicorn Worker Killer’s config.ru settings did not quite work for my setup as ENV[‘RAILS_ENV’] was not yet defined at this point of the code so everything inside the if statement was ignored.
I had to use ENV[‘RAKE_ENV’] instead, but on the gem’s documentation (https://github.com/kzk/unicorn-worker-killer) they don’t even put an if statement so that’s probably fine to get rid of it altogether.