11

Musimy użyć delayed_job (lub innego procesora działającego w tle), aby uruchomić zadania w tle, ale nie możemy zmieniać skryptów rozruchowych/rozruchowych -levels na serwerze. Oznacza to, że demon nie ma gwarancji, że pozostanie dostępny, jeśli dostawca ponownie uruchomi serwer (ponieważ demon byłby uruchamiany przez recepturę capistrano, która jest uruchamiana tylko raz dla każdego wdrożenia).Uruchom lub upewnij się, że zadanie opóźnione działa, gdy aplikacja/serwer zostanie ponownie uruchomiony.

Obecnie najlepszym sposobem, w jaki mogę zapewnić, że demon delayed_job jest zawsze uruchomiony, jest dodanie inicjalizatora do naszej aplikacji Railsowej, która sprawdza, czy demon jest uruchomiony. Jeśli nie działa, inicjator uruchamia demona, w przeciwnym razie po prostu pozostawia go.

Pytanie zatem brzmi: w jaki sposób wykryjemy, że demon Delayed_Job działa z poziomu skryptu? (Powinniśmy być w stanie dość łatwo uruchomić demona, trochę nie wiem, jak wykryć, czy ktoś jest już aktywny).

Ktoś ma jakieś pomysły?

Pozdrawiam, Bernie

Na podstawie poniższej odpowiedzi, to co wymyśliłem. Wystarczy umieścić go w config/inicjalizatorów i gotowe:

#config/initializers/delayed_job.rb 

DELAYED_JOB_PID_PATH = "#{Rails.root}/tmp/pids/delayed_job.pid" 

def start_delayed_job 
    Thread.new do 
    `ruby script/delayed_job start` 
    end 
end 

def process_is_dead? 
    begin 
    pid = File.read(DELAYED_JOB_PID_PATH).strip 
    Process.kill(0, pid.to_i) 
    false 
    rescue 
    true 
    end 
end 

if !File.exist?(DELAYED_JOB_PID_PATH) && process_is_dead? 
    start_delayed_job 
end 
+0

W twojej odpowiedzi, czy nie powinniśmy również dostarczać '-e production'? – nathanvda

+0

Korzystanie z rails3 to rozwiązanie nie działa dla mnie. Rozpoczęcie procesu jest kompletnie błędne: nadal uruchamia dodatkowe zadania. Wróciłem do zadań capistrano :) – nathanvda

Odpowiedz

5

sprawdzić istnienie pliku demony PID (File.exist? ...). Jeśli tak jest, to zakładaj, że działa, uruchom go ponownie.

+0

Świetnie! Brzmi łatwo! Czy zdarzy ci się, gdzie mogę znaleźć ten plik? – btelles

+1

Znajdziesz plik w folderze tmp/pids swojej aplikacji. Możesz również sprawdzić, czy istnieje proces z identyfikatorem z pliku. Plik PID może nadal istnieć po awarii. –

+0

Doskonale! Dzięki! Na razie przegłosuję i czekam, czy są jakieś inne alternatywy na dzień lub 2. – btelles

9

Kilka innych pomysłów na porządki: "Początek" nie jest potrzebny. Powinieneś uratować "brak takiego procesu", aby nie uruchamiać nowych procesów, gdy coś pójdzie nie tak. Uratuj "nie ma takiego pliku lub katalogu", aby uprościć ten warunek.

DELAYED_JOB_PID_PATH = "#{Rails.root}/tmp/pids/delayed_job.pid" 

def start_delayed_job 
    Thread.new do 
    `ruby script/delayed_job start` 
    end 
end 

def daemon_is_running? 
    pid = File.read(DELAYED_JOB_PID_PATH).strip 
    Process.kill(0, pid.to_i) 
    true 
rescue Errno::ENOENT, Errno::ESRCH # file or process not found 
    false 
end 

start_delayed_job unless daemon_is_running? 

Należy pamiętać, że ten kod nie zadziała, jeśli uruchomi się więcej niż jednego pracownika. I sprawdź argument "-m" skryptu/delayed_job, który spawnuje proces monitorowania wraz z demonem (ami).

0

Dziękuję za rozwiązanie zawarte w pytaniu (i odpowiedź, która go zainspirowała :-)), działa dla mnie, nawet z wieloma pracownikami (Rails 3.2.9, Ruby 1.9.3p327).

Martwi mnie to, że mogę zapomnieć o ponownym uruchomieniu delayed_job po wprowadzeniu pewnych zmian w lib, na przykład, powodując mi debugowanie przez wiele godzin, zanim się o tym dowiem.

I dodaje następujące do mojego pliku script/rails w celu umożliwienia kod podany w pytaniu do wykonania za każdym razem zaczynamy szyn, ale nie za każdym razem pracownik rozpoczyna:

puts "cleaning up delayed job pid..." 
dj_pid_path = File.expand_path('../../tmp/pids/delayed_job.pid', __FILE__) 
begin 
    File.delete(dj_pid_path) 
rescue Errno::ENOENT # file does not exist 
end 
puts "delayed_job ready." 

Trochę wadę, że I” Z tym jednak stoi, że jest na przykład wywoływany z rails generate. Nie poświęciłem wiele czasu na szukanie rozwiązania, ale sugestie są mile widziane :-)

Pamiętaj, że jeśli używasz jednorożca, możesz dodać ten sam kod do config/unicorn.rb przed rozmową before_fork.

- edycja: Po gra się trochę więcej z powyższych rozwiązań, skończyło się w następujący sposób:

stworzyłem plik script/start_delayed_job.rb z treścią:

puts "cleaning up delayed job pid..." 
dj_pid_path = File.expand_path('../../tmp/pids/delayed_job.pid', __FILE__) 

def kill_delayed(path) 
    begin 
    pid = File.read(path).strip 
    Process.kill(0, pid.to_i) 
    false 
    rescue 
    true 
    end 
end 

kill_delayed(dj_pid_path) 

begin 
    File.delete(dj_pid_path) 
rescue Errno::ENOENT # file does not exist 
end 

# spawn delayed 
env = ARGV[1] 
puts "spawing delayed job in the same env: #{env}" 

# edited, next line has been replaced with the following on in order to ensure delayed job is running in the same environment as the one that spawned it 
#Process.spawn("ruby script/delayed_job start") 
system({ "RAILS_ENV" => env}, "ruby script/delayed_job start") 

puts "delayed_job ready." 

teraz Mogę wymagać tego pliku w dowolnym miejscu, w tym "script/rails" i "config/unicorn.rb", wykonując:

# in top of script/rails 
START_DELAYED_PATH = File.expand_path('../start_delayed_job', __FILE__) 
require "#{START_DELAYED_PATH}" 

# in config/unicorn.rb, before before_fork, different expand_path 
START_DELAYED_PATH = File.expand_path('../../script/start_delayed_job', __FILE__) 
require "#{START_DELAYED_PATH}" 
0

nie super, ale działa

zastrzeżenie: mówię nie super, bo to powoduje okresową restart, który dla wielu nie będzie pożądane. Po prostu próba uruchomienia może spowodować problemy, ponieważ implementacja DJ-a może zablokować kolejkę, jeśli zostaną utworzone duplikaty instancji.

Można zaplanować zadania, które są uruchamiane okresowo w celu rozpoczęcia pracy (zadań). Ponieważ DJ traktuje polecenia startowe jako no-ops, gdy zadanie jest już uruchomione, po prostu działa. Takie podejście uwzględnia również przypadek, w którym DJ umiera z jakiegoś powodu, poza restartem hosta.

# crontab example 
0 * * * * /bin/bash -l -c 'cd /var/your-app/releases/20151207224034 && RAILS_ENV=production bundle exec script/delayed_job --queue=default -i=1 restart' 

Jeśli używasz gem jak whenever jest to całkiem proste.

every 1.hour do 
    script "delayed_job --queue=default -i=1 restart" 
    script "delayed_job --queue=lowpri -i=2 restart" 
end 
Powiązane problemy