Send emails via sidekiq (#380)

* add sidekiq web view if the user is an administrator

* add sidekiq setup configuration and support

* update devise to use delivery_later method and update test

* update conversation to use deliver_later instead of deliver

* Update Routes

* Add Procfile for Heroku One-Click Start

* updating docs

* update concurrency and Procfile for supporting Heroku Free Dyno

* update Procfile.dev
This commit is contained in:
Anto Dominic
2019-12-25 03:03:02 +05:30
committed by Sojan Jose
parent 335e7487e6
commit 4e9290ad76
13 changed files with 53 additions and 5 deletions

2
Procfile Normal file
View File

@@ -0,0 +1,2 @@
web: bin/rails server -p $PORT -e $RAILS_ENV
worker: bundle exec sidekiq -C config/sidekiq.yml

View File

@@ -1,2 +1,3 @@
backend: bin/rails s -p 3000 backend: bin/rails s -p 3000
frontend: bin/webpack-dev-server frontend: bin/webpack-dev-server
worker: bundle exec sidekiq

View File

@@ -99,7 +99,7 @@ class Conversation < ApplicationRecord
def send_email_notification_to_assignee def send_email_notification_to_assignee
return if self_assign?(assignee_id) return if self_assign?(assignee_id)
AssignmentMailer.conversation_assigned(self, assignee).deliver if saved_change_to_assignee_id? && assignee_id.present? AssignmentMailer.conversation_assigned(self, assignee).deliver_later if saved_change_to_assignee_id? && assignee_id.present?
end end
def self_assign?(assignee_id) def self_assign?(assignee_id)

View File

@@ -86,6 +86,10 @@ class User < ApplicationRecord
after_create :notify_creation after_create :notify_creation
after_destroy :notify_deletion after_destroy :notify_deletion
def send_devise_notification(notification, *args)
devise_mailer.send(notification, self, *args).deliver_later
end
def set_password_and_uid def set_password_and_uid
self.uid = email self.uid = email
end end

View File

@@ -33,6 +33,8 @@ Rails.application.configure do
config.active_storage.service = :local config.active_storage.service = :local
# Don't care if the mailer can't send. # Don't care if the mailer can't send.
config.active_job.queue_adapter = :sidekiq
config.action_mailer.raise_delivery_errors = false config.action_mailer.raise_delivery_errors = false
config.action_mailer.perform_caching = false config.action_mailer.perform_caching = false

View File

@@ -75,6 +75,7 @@ Rails.application.configure do
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found). # the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true config.i18n.fallbacks = true
config.active_job.queue_adapter = :sidekiq
# Send deprecation notices to registered listeners. # Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify config.active_support.deprecation = :notify

View File

@@ -75,6 +75,7 @@ Rails.application.configure do
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found). # the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true config.i18n.fallbacks = true
config.active_job.queue_adapter = :sidekiq
# Send deprecation notices to registered listeners. # Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify config.active_support.deprecation = :notify

View File

@@ -43,6 +43,7 @@ Rails.application.configure do
# The :test delivery method accumulates sent emails in the # The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array. # ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test config.action_mailer.delivery_method = :test
config.active_job.queue_adapter = :test
# Print deprecation notices to the stderr. # Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr config.active_support.deprecation = :stderr

View File

@@ -90,6 +90,12 @@ Rails.application.routes.draw do
end end
end end
# Sidekiq Web UI
require 'sidekiq/web'
authenticate :user, lambda { |u| u.administrator? } do
mount Sidekiq::Web => '/sidekiq'
end
# Used in mailer templates # Used in mailer templates
resource :app, only: [:index] do resource :app, only: [:index] do
resources :conversations, only: [:show] resources :conversations, only: [:show]

23
config/sidekiq.yml Normal file
View File

@@ -0,0 +1,23 @@
# Sample configuration file for Sidekiq.
# Options here can still be overridden by cmd line args.
# Place this file at config/sidekiq.yml and Sidekiq will
# pick it up automatically.
---
:verbose: false
:concurrency: 10
:timeout: 25
# Sidekiq will run this file through ERB when reading it so you can
# even put in dynamic logic, like a host-specific queue.
# http://www.mikeperham.com/2013/11/13/advanced-sidekiq-host-specific-queues/
:queues:
- critical
- default
- low
- mailers
# you can override concurrency based on environment
production:
:concurrency: 3
staging:
:concurrency: 15

View File

@@ -23,8 +23,15 @@ docker-compose run rails bundle exec rails db:reset
docker-compose run --service-port rails docker-compose run --service-port rails
``` ```
open another terminal and also run below command to run sidekiq in a separate service
```
docker-compose run rails bundle exec sidekiq
```
* Access the rails app frontend by visiting `http://0.0.0.0:3000/` * Access the rails app frontend by visiting `http://0.0.0.0:3000/`
* Access Mailhog inbox by visiting `http://0.0.0.0:8025/` (You will receive all emails going out of the application here) * Access Mailhog inbox by visiting `http://0.0.0.0:8025/` (You will receive all emails going out of the application here)
* Access Sidekiq Web UI by visiting `http://0.0.0.0:3000/sidekiq` (You need to login with administrator account to access sidekiq)
you can also use the below command instead to run the app and see the full logs. you can also use the below command instead to run the app and see the full logs.

View File

@@ -6,7 +6,7 @@ RSpec.describe 'Confirmation Instructions', type: :mailer do
describe :notify do describe :notify do
let(:confirmable_user) { FactoryBot.build(:user, inviter: inviter_val) } let(:confirmable_user) { FactoryBot.build(:user, inviter: inviter_val) }
let(:inviter_val) { nil } let(:inviter_val) { nil }
let(:mail) { confirmable_user.send_confirmation_instructions } let(:mail) { Devise::Mailer.confirmation_instructions(confirmable_user, nil, {}) }
it 'has the correct header data' do it 'has the correct header data' do
expect(mail.reply_to).to contain_exactly('accounts@chatwoot.com') expect(mail.reply_to).to contain_exactly('accounts@chatwoot.com')

View File

@@ -35,7 +35,7 @@ RSpec.describe Conversation, type: :model do
allow(Rails.configuration.dispatcher).to receive(:dispatch) allow(Rails.configuration.dispatcher).to receive(:dispatch)
allow(AssignmentMailer).to receive(:conversation_assigned).and_return(assignment_mailer) allow(AssignmentMailer).to receive(:conversation_assigned).and_return(assignment_mailer)
allow(assignment_mailer).to receive(:deliver) allow(assignment_mailer).to receive(:deliver_later)
Current.user = old_assignee Current.user = old_assignee
conversation.update( conversation.update(
@@ -68,7 +68,7 @@ RSpec.describe Conversation, type: :model do
# send_email_notification_to_assignee # send_email_notification_to_assignee
expect(AssignmentMailer).to have_received(:conversation_assigned).with(conversation, new_assignee) expect(AssignmentMailer).to have_received(:conversation_assigned).with(conversation, new_assignee)
expect(assignment_mailer).to have_received(:deliver) if ENV.fetch('SMTP_ADDRESS', nil).present? expect(assignment_mailer).to have_received(:deliver_later) if ENV.fetch('SMTP_ADDRESS', nil).present?
end end
end end