Last active
May 2, 2023 15:22
-
-
Save sephraim/aacb23d5149127630265c9987979b163 to your computer and use it in GitHub Desktop.
[ActiveJob / DelayedJob example class] with tests and Docker Compose setup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
volumes: | |
postgresql: | |
name: automotiontv-postgresql | |
external: true | |
x-restart_policy: &default_restart_policy | |
deploy: | |
restart_policy: | |
condition: on-failure | |
delay: 5s | |
max_attempts: 3 | |
services: | |
web: | |
<< : *default_restart_policy | |
build: . | |
image: automotiontv-server | |
container_name: automotiontv-server | |
env_file: .env | |
volumes: | |
- .:/app | |
ports: | |
- 3000:3000 | |
command: ["wait-for-it", "--strict", "--timeout=60", "db:5432", "--", "./run.sh"] | |
depends_on: | |
- db | |
delayed_job: | |
<< : *default_restart_policy | |
build: . | |
image: automotiontv-server | |
container_name: delayed-job | |
env_file: .env | |
volumes: | |
- .:/app | |
command: ["wait-for-it", "--strict", "--timeout=60", "web:3000", "--", "bin/rails", "jobs:work"] | |
depends_on: | |
- db | |
- web | |
db: | |
image: postgres:15 | |
container_name: automotiontv-db | |
env_file: .env | |
volumes: | |
- postgresql:/var/lib/postgresql/data | |
- .:/app | |
ports: | |
- '5432:5432' | |
adminer: | |
image: adminer | |
container_name: adminer | |
ports: | |
- 8080:8080 | |
depends_on: | |
- db |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
# A job to generate an account locations report using the Google Places API | |
class GenerateGooglePlacesReportJob < ApplicationJob | |
queue_as :default | |
before_enqueue :prevent_job_duplication, :validate_email_address | |
before_perform :validate_email_address | |
after_perform :send_email | |
class << self | |
# Determine if job is already enqueued | |
# | |
# @return [Boolean] | |
def job_already_enqueued? | |
Delayed::Job.any? { |j| j.handler.include?(" job_class: #{self}\n") } | |
end | |
end | |
# Generate an account locations report using the Google Places API | |
# | |
# Email is passed into this method in order to be used by the .send_email method. | |
# | |
# @param email_address [String] Email address to send download link to | |
# @return [void] | |
def perform(email_address:) # rubocop:disable Lint/UnusedMethodArgument | |
client = GooglePlacesApiClient.new | |
client.accounts_with_places(format: :csv_file, filename: GooglePlacesApiClient::DEFAULT_CSV_FILEPATH) | |
end | |
private | |
# Prevent this job from being enqueued if email address is invalid | |
# | |
# @private | |
# | |
# @return [void] | |
def validate_email_address | |
return if email_address.match?(URI::MailTo::EMAIL_REGEXP) | |
msg = "Unable to enqueue #{self.class} because email address is invalid." | |
Rails.logger.info msg | |
throw :abort | |
end | |
# Prevent this job from being duplicated in the queue. It should only generate one report at a time. | |
# | |
# @private | |
# | |
# @return [void] | |
def prevent_job_duplication | |
return unless self.class.job_already_enqueued? | |
msg = "Unable to enqueue #{self.class} because it is already enqueued." | |
Rails.logger.info msg | |
throw :abort | |
end | |
# Send email to the user letting them know the report is ready to download | |
# | |
# @private | |
# | |
# @return [void] | |
def send_email | |
Rails.logger.info "Sending Google Places report email to #{email_address}" | |
Notifications.google_places_report_ready(email: email_address).deliver_now | |
end | |
# Email address to send the download link to | |
# | |
# @private | |
# | |
# @return [String] | |
def email_address | |
@email_address ||= arguments.first[:email_address].to_s | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require 'rails_helper' | |
RSpec.describe GenerateGooglePlacesReportJob, type: :job do | |
let(:tmpdir) { Dir.mktmpdir } | |
let(:csv_path) { File.join(tmpdir, GooglePlacesApiClient::DEFAULT_CSV_FILENAME) } | |
let(:perform_now) { described_class.perform_now(email_address: '[email protected]') } | |
let(:perform_later) { described_class.perform_later(email_address: '[email protected]') } | |
before(:example) do | |
# Generate test reports in a tmp directory | |
stub_const('GooglePlacesApiClient', GooglePlacesApiClient) | |
stub_const('GooglePlacesApiClient::DEFAULT_CSV_FILEPATH', csv_path) | |
end | |
after(:example) do | |
# Cleanup tmp directory | |
FileUtils.rm_rf(tmpdir) | |
end | |
context 'when the job is not already running' do | |
it 'enqueues a background job' do | |
expect { perform_later }.to have_enqueued_job(described_class) | |
end | |
it 'creates a report file' do | |
perform_now | |
expect(File).to exist(csv_path) | |
end | |
it 'sends an email' do | |
expect { perform_now }.to change { ActionMailer::Base.deliveries.count }.by(1) | |
end | |
end | |
context 'when the job is already running' do | |
before(:example) do | |
allow(GenerateGooglePlacesReportJob).to receive(:job_already_enqueued?).and_return(true) | |
end | |
it 'prevents the job from being duplicated' do | |
expect { perform_later }.not_to have_enqueued_job(described_class) | |
end | |
end | |
context 'when the email address is invalid' do | |
let(:invalid_job) { described_class.perform_later(email_address: 'not_a_real_email') } | |
it 'prevents the job from being performed' do | |
expect { invalid_job }.not_to have_enqueued_job(described_class) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment