12/08/2018, 13:41

gửi mail tự động với whenever và sidekiq

Gửi mail là một trong những chức năng không thể thiếu của một trang web, mail tự động nhằm mục đích báo cáo tình hình hoạt động của một trang web cho người quản lý cũng như các user. Bắt đầu với gửi mail tự động, ta bắt đầu vói việc lập lịch bằng whenever Thêm gem whenever vào gem file và ...

Gửi mail là một trong những chức năng không thể thiếu của một trang web, mail tự động nhằm mục đích báo cáo tình hình hoạt động của một trang web cho người quản lý cũng như các user.

Bắt đầu với gửi mail tự động, ta bắt đầu vói việc lập lịch bằng whenever

Thêm gem whenever vào gem file và bundle

gem 'whenever', :require => false

Khởi tạo file thực thi

bundle install
wheneverize .

Sau khi khởi chạy dòng lệnh trên, ta bắt đầu config thời gian chạy.

+---------------- minute (0 - 59)
|  +------------- hour (0 - 23)
|  |  +---------- day of month (1 - 31)
|  |  |  +------- month (1 - 12)
|  |  |  |  +---- day of week (0 - 6) (Sunday=0)
|  |  |  |  |
*  *  *  *  *  command to be executed

Example

#config/schedule.rb
every 1.minutes do
  rake "db:migrate:reset"
end

Sau khi config xong thời gian tự động chạy, ta update cho hệ thống

whenever --update-crontab
#[write] crontab file updated

Ta có thể thấy lịch trình trên terminal theo định dạng

* * * * * /bin/bash -l -c 'cd /home/ngocha/workspace/fts_62 && RAILS_ENV=production bundle exec rake db:migrate:reset --silent'

Ngoài ra còn 1 số lệnh để cài đặt hệ thống

crontab -l : xem lịch hệ thống
crontab -r : xóa lịch hệ thống

Ở đây, chúng ta đã hoàn thành lập lịch cho hệ thống với 1 lệnh rake, nhưng chúng ta cần phải kết hợp với send mail sử dụng sidekiq.

Đầu tiên, chúng ta cần phải gửi mail bằng hệ thống mặc định của rails.

#app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
  default from: Settings.mail_from
  def mail_month course
    @supervisor = course.supervisor
    ...
    mail to: @supervisor.email, subject: t("mail.mail_month", content: @course.content)
  end
end
#app/view/user_mailer/mail_month.html.erb
<h1><%= @supervisor.name %></h1>
...
#config/environments/development.rb
  config.consider_all_requests_local       = true
  config.action_controller.perform_caching = false
  config.action_mailer.default_url_options ={host: "localhost", port: 3000}
  # Don't care if the mailer can't send.
  config.active_job.queue_adapter = :sidekiq
  config.active_job.queue_name_prefix = "mysite"
  config.active_job.queue_name_delimiter = "_"

  config.action_mailer.perform_deliveries = true
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address: "smtp.gmail.com",
    port: 587,
    domain: "example.com",
    user_name: ENV["GMAIL_USERNAME"],
    password: ENV["GMAIL_PASSWORD"],
    authentication: "plain",
enable_starttls_auto: true}

Ở đây, ta có thể test việc gửi mail bằng cách gọi

UserMailer.mail_month(course).deliver_now

Hãy nhớ config tài khoản Gmail của bạn cho phép truy cập với độ tin cậy thấp và unlock captcha. Nếu bạn chưa config hãy config theo link dưới đây

https://www.google.com/settings/security/lesssecureapps
https://accounts.google.com/b/0/DisplayUnlockCaptcha

Sau khi test đã gửi được mail với mail thường, chúng ta sẽ tiếp tục đưa mail chạy qua sidekiq nhằm mục đích giảm tải cho sever.

Khi bạn gửi mail qua sidekiq, sidekiq sẽ tạo ra một hệ thống gửi mail chạy độc lập với sever. Do đó nó sẽ giảm tải cho sever trong quá trình gửi mail.

gem "sidekiq"
bundle install

Sau đó ta tạo folder workers trong thư mục app. và tạo các file worker trong thư mục này

#app/workers/monthly_worker.rb
class MonthlyWorker
  include Sidekiq::Worker

  MAIL_MONTH = 1

  def perform action
    case action
    when MAIL_MONTH
      Course.all.each do |course|
        send_email_when_end_month course
      end
    end
  end

  private
  def send_email_when_end_month course
    UserMailer.mail_month(course).deliver_now
  end
end

Nhớ bật sever sidekiq trong terminal bằng lệnh bundle exec sidekiq. Tới đây chúng ta đã thành công trong việc gửi mail thông qua sidekiq.

Việc cuối cùng chúng ta cần làm là gắn lịch hệ thống với tiến trình gửi mail của sidekiq

Như đã nói ở trên, sau mỗi chu trình lập lịch whenever sẽ chạy lệnh rake

#config/schedule.rb
rake "db:migrate:reset"

một lần. Ở đây, ta cần tìm hiểu về lệnh rake 1 chút

Để chạy được lệnh rake ta cần tạo foldler tasks trong thư mục lib và tạo 1 file :rake trong đó.

#lib/tasks/job:rake
namespace :job do
  desc "TODO"
  task mailmonth: :environment do
    MonthlyWorker.perform_async MonthlyWorker::MAIL_MONTH
  end
end

Ta cần config lại đia chỉ rake của whenever để nó chỉ tới mail hệ thống.

#config/schedule.rb
set :environment, "development"
#để kiểm soát lỗi gửi mail hệ thống
set :output, ".../log.log" #đường dẫn tuyệt đối

every "0 0 1 * *" do
  rake "job:mailmonth"
end

Ta có thể test thử bằng rails c của terminal để xem sidekiq có chạy không bằng lệnh rake "job:mailmonth" cuối cùng ta update lại crontab của whenever bằng lệnh whenever --update-crontab

Có thể 1 số bạn sẽ không gửi được mail hoặc gửi mail báo lỗi ` ``undefine bundler```. Trong trường hợp này chúng ta cần chạy bundle cho vendor.

bundle install --path=vendor/bundle

Việc gửi mail tự động đến đây đã hoàn thành, chúc các bạn thành công trong công việc. Cám ơn đã xem bài viết của mình.

tài liệu tham khảo

https://launchschool.com/blog/cron-jobs-and-rails

https://github.com/javan/whenever

https://github.com/mperham/sidekiq/wiki/Getting-Started

0