2011-04-26 28 views
22

Vì vậy, việc gửi USR2 đến Unicorn thật tuyệt vời - nó khởi động một bản gốc mới với bản sao mã mới của bạn và tự động nhận bất kỳ thay đổi nào. Ngọt. Câu hỏi của tôi là: làm thế nào để ngăn chặn chủ cũ? Cách rõ ràng chấp nhận là trong một before_fork:Khởi động lại Unicorn bằng USR2 - bỏ chủ cũ

before_fork do |server,worker| 
    old_pid = '/var/www/current/tmp/pids/unicorn.pid.oldbin' 
    if File.exists?(old_pid) && server.pid != old_pid 
    begin 
     Process.kill("QUIT", File.read(old_pid).to_i) 
    rescue Errno::ENOENT, Errno::ESRCH 
     # someone else did our job for us 
    end 
    end 
end 

Vấn đề với điều này là ngay sau khi chủ mới (và công nhân mới) đều được sinh ra, họ giết thầy cũ. Vì vậy, bất kỳ yêu cầu đến trang web chỉ cần ngồi đó chờ đợi cho nhân viên mới bắt đầu, thường trong vài giây trong khi toàn bộ ngăn xếp Rails tải.

Nếu tôi xóa tất cả mọi thứ trước đây, tôi có thể tải lại trình duyệt của mình cả ngày và mọi yêu cầu được điền nhanh, không có chỉ báo khi nào chủ mới tiếp quản (khác thay vì nhìn thấy các thay đổi mã của tôi xuất hiện ngay bây giờ). Nhưng, ông chủ cũ đã treo xung quanh cho đến khi tôi gửi nó một cách QUIT.

Theo như tôi biết, không có gọi lại khi nhân viên hoàn tất tải và sẵn sàng phục vụ khách hàng. Đó thực sự là cuộc gọi lại mà tôi đang tìm kiếm. Tôi luôn luôn có thể tạo ra một initializer trong Rails chính nó tìm kiếm một bậc thầy cũ và giết chết nó, nhưng điều đó làm cho trái tim tôi đau chỉ nghĩ về nó.

Phải có cách!

+0

Tôi chắc chắn rằng after_fork được gọi bởi công nhân khi họ tải xong, bạn có thể đặt mã ở đó .. –

Trả lời

16

Tôi đã giải quyết một phần vấn đề này: hành vi tôi thấy là do không sử dụng preload_app true. Nếu bạn đã thiết lập này thì toàn bộ ứng dụng được tải bởi các bậc thầy và công nhân rất nhanh để đẻ trứng. Vì vậy, nếu công nhân đầu tiên giết chủ cũ tại thời điểm này thì không sao vì nhân viên nói có thể bắt đầu phục vụ yêu cầu ngay lập tức!

Nếu bạn không thể sử dụng preload_app true thì đặt cược tốt nhất của bạn có thể là di chuyển hành vi cũ-pid-quit đó vào trình khởi tạo Rails để công nhân đầu tiên trả về ứng dụng của bạn có thể giết chủ cũ sau khi Rails khởi động và sẵn sàng phục vụ các yêu cầu.

+0

Bạn đang chạy bao nhiêu quy trình công nhân? – Ivan

8

Dường như việc gửi tín hiệu HUP tới máy chủ Unicorn là một giải pháp thay thế tốt hơn nếu preload_appfalse.

Từ http://unicorn.bogomips.org/SIGNALS.html:

HUP - load lại cấu hình tập tin và duyên dáng khởi động lại tất cả các công nhân. Nếu lệnh “preload_app” là sai (mặc định là ), thì nhân viên cũng sẽ chọn bất kỳ thay đổi mã ứng dụng nào khi khởi động lại.

+4

Về mặt lý thuyết, nếu preload_app là đúng, bạn nên sử dụng USR2 + QUIT 'Nếu “preload_app” là đúng, thì thay đổi mã ứng dụng sẽ không có hiệu lực; USR2 + QUIT phải được sử dụng để tải mã mới hơn trong trường hợp này. ' – astjohn

+0

Rất tiếc. Tôi có nghĩa là để nói "nếu preload_app là sai". –

+1

Nếu điều này đúng, nó không còn nữa: HUP tải lại ứng dụng ngay cả khi preload_app là đúng. – Kevin

3

Đây là những gì tôi có trong khối before_fork tôi:

old_pid = "#{server.config[:pid]}.oldbin" 
    if old_pid != server.pid 
    begin 
     sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU 
     Process.kill(sig, File.read(old_pid).to_i) 
    rescue Errno::ENOENT, Errno::ESRCH 
    end 
    end 

Để khởi động lại lân của tôi, tôi có một kịch bản bash rằng có một phương pháp như thế này:

if sig USR2 && sig 0 && oldsig QUIT 
then 
    n=$TIMEOUT 
    while test -s $old_pid && test $n -ge 0 
    do 
     printf '.' && sleep 1 && n=$(($n - 1)) 
    done 
    echo 

    if test $n -lt 0 && test -s $old_pid 
    then 
     echo >&2 "$old_pid still exists after $TIMEOUT seconds" 
     exit 1 
    fi 
    exit 0 
fi 
echo >&2 "Couldn't upgrade, starting '$CMD' instead" 
$CMD 
;; 

Các kịch bản bash gửi tín hiệu USR2, loại bỏ con kỳ lân mới và tạo ra pid cũ. Sau đó nó sẽ gửi tín hiệu QUIT cũ bằng cách sử dụng pid cũ.

Quy trình này hoạt động thực sự tốt và được lấy từ Where Unicorns go to die: Watching unicorn workers with monit, một tài nguyên tuyệt vời.

+0

USR2 không tạo 'oldbin' cho tôi, điều gì có thể là lý do? – juanpastas

Các vấn đề liên quan