Skip to content

Instantly share code, notes, and snippets.

@benjaminkreen
Created February 4, 2019 21:09
Show Gist options
  • Save benjaminkreen/3467b5061054394d13dc7d9eb77579ad to your computer and use it in GitHub Desktop.
Save benjaminkreen/3467b5061054394d13dc7d9eb77579ad to your computer and use it in GitHub Desktop.
rails implementation transactional emailing with queueing
# app/controllers/events_controller.rb
class EventsController < ApplicationController
def create
Event.create(params.permit(:event_type, :doi, :event_data))
render json: {}, status: :ok
end
end
# app/models/event.rb
class Event < ActiveRecord
# not sure if this is the best place for this mapping
# could beling in DB
EVENT_QUEUE_TIME_MAP = {
'event_1' => 0,
'event_2' => 24
}
after_create :perform_email_job, if: :enqueue_job?
def perform_email_job
EmailEventJob.set(wait: queue_time.hours).perform_later(id, doi, event_type, queue_time.zero?)
# do we care to handle unlisted events?
end
def queue_time
EVENT_QUEUE_TIME_MAP[event_type]
end
def enqueue_job?
# there might be some sort of db locking we'd need to implement
# to prevent some sort of race condition?
queue_time.zero? || Event.where(doi: doi, event_type: event_type).count == 1
end
end
# app/jobs/email_event_job.rb
class EmailEventJob < ActiveJob
def perform(event_id, doi, event_type, use_id)
where_args = use_id ? { id: event_id } : { doi: doi, event_type: event_type }
events = Event.where(where_args) # maybe add some sort of DB lock
return if events.empty? # this might happen? Ideally not.
recepients = get_author_emails(doi)
# only email client specific api call, can be swapped out
SendgridClient.send_email(event_type, recepients, events.pluck(:event_data)) # should raise error if fails
events.destroy_all # we can soft delete if we want to keep a record
end
def get_author_emails(doi)
# TODO: this needs to get figured out and probably cached
end
end
# lib/sendgrid_client.rb
require 'sendgrid-ruby'
require 'json'
include SendGrid
class SendgridClient
EVENT_TEMPLATE_MAP = {
'event_1' => 'abc123',
'event_2' => 'def456'
}
class << self
def send_email(event_type, recepients, event_data)
mail = Mail.new
mail.template_id = EVENT_TEMPLATE_MAP[event_type]
mail.from = Email.new(email: 'no-reply@plos.org')
personalization = Personalization.new
recepients.each do |recepient|
personalization.add_to(Email.new(email: recepient))
end
# we kinda assume the first set of data coming in is pretty much
# tailored for emailing, but we could also massage it here too.
personalization.add_dynamic_template_data(events: event_data)
mail.add_personalization(personalization)
sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'], host: 'https://api.sendgrid.com')
sg.client.mail._('send').post(request_body: mail.to_json)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment