Hej
W dzisiejszym odcinku chciałbym poruszyć niezwykle istotny temat jakim są background joby. W poprzednim odcinku pokazywałem wam jak wysyłać maile, ale w tamtym przypadku musimy czekać na zakończenie wysyłania by dostać odpowiedź z serwera. Dodatkowo do maila może być generowany jakiś duży załącznik więc lepiej by takie rzeczy działy się w tle.
W tytule jest jeszcze jedno hasło, active job. Kolejny raz Railsy mają już gotowe rozwiązanie na popularny problem. Active Job nie tylko odpowiada za pracę w tlę ale też pracę kolejek. Można też ustawić wykonanie workera o danym czasie. Np powiadomienia mailowe o północy.
Ale tak jak w przypadku ActiveRecorda gdzie ten jest warstwą abstrakcji na bazie danych tak tutaj pod spodem musi działać jakiś inny gem np sidekiq Delayed Job albo Resque.
Tworzenie jobów
jeżeli na pierwszy przykład weźmiemy maila z poprzedniego odcinka to wystarczy zmienić
ContactMailer.contact_message(@contact_message).deliver_now
na
ContactMailer.contact_message(@contact_message).deliver_later
wtedy z automatu mail trafi na kolejkę. A akcja naszego kontrolera wykona się niezależnie od tego czy mail się wyślę czy nie.
zróbmy jeszcze jeden przykład. Tym razem utwórzmy joba
do tego celu użyjemy gneratora z railsów
rails generate job messages_cleanup
utworzy to nam plik który wygląda tak
class MessagesCleanupJob < ApplicationJob
queue_as :default
def perform(*guests)
# Do something later
end
end
zmieńmy go trochę by rzeczywiście coś zrobił
class MessagesCleanupJob < ApplicationJob
queue_as :default
def perform(message)
message.delete
end
end
w ten sposób jako argument przyjmuje message, który jest nasza wiadomością z kontrolera, następnie usuwa wiadomość. Zastanawiacie się może po co usuwać wiadomość.
przejdźmy więc do kontrolera
po wysłaniu maila mogli byśmy od razu odpalić taką komende
MessagesCleanupJob.perform_later(@contact_message)
wtedy od razu czyszczenie trafi na kolejkę, w przypadku tak małej aplikacji jak nasza wykona się to natychmiastowo
ale możemy to zmienić na
MessagesCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later(@contact_message)
w ten sposób dopiero jutro usunie się nasza wiadomość. W realnym świecie te zasady pewnie nie mają sensu, ale to jest tylko przykład.
konfiguracja
najprostszym gemem będzie zapewne Delayed::Job
używa on tej samej bazy danych co reszta aplikacji, więc po za nową tabelą nie potrzebujemy za wiele robić
dodajmy więc ten gem do naszego Gemfila
gem 'delayed_job_active_record'
i odpalmy bundle install
następnie należy odpalić generator rails generate delayed_job:active_record
i migracje rails db:migrate
w appliacation.rb musimy ustawić by delayed job był odpowiedzialny za naszą kolejkę config.active_job.queue_adapter = :delayed_job
na koniec musimy pamiętać by po za rails server
odpalić jeszcze rake jobs:work
jeżeli będziemy chcieli to zakończyć możemy nacisnąć ctrl+c
Heroku
tak jak w innych moich filmach by pokazać jak coś działa na serwerze posłużę się heroku. korzystanie z background jobów na heroku jest bardzo proste. Niestety server i worker nie mogą korzystać z tej samej instancji. Na szczęście oba mogą korzystać z darmowej. Problem zaczyna się gdy przechodzimy na płatne, bo heroku wymusza by oba miały tą samą konfiguracje, ale można je osobno skalować.
Potrzebujemy utworzyć nowy plik Procfile
a w nim dodać komende to odpalania servera
web: bundle exec rails server -p $PORT
ale też naszego workera
worker: bundle exec rake jobs:work
po wrzuceniu zmian na heroku wszystko już będzie działać
Sidekiq
wartym wspomnienia jest jeszcze gem sidekiq który jest chyba najlepszym rozwiązaniem do zarządzania kolejkami. Z racji, że korzysta on z osobnej bazy danych. Redisa. To poświęcę mu osobne nagranie
Na dzisiaj to już wszystko. Dziękuje za oglądanie Życzę miłego kodowania!