Rails cron job run - ruby-on-rails

I have a rails multitenant application.
And I have some branch listing in my app with branch_name and branch_email.
I want to run cronjob to send "good morning" email to each branch of each tenant.
I am using Postgres sql schemes as tenants.

Use Sidekiq gem as a background worker and use Sidekiq Cron gem for scheduling.
Create a Worker to send email to each branch of each tenant.
create a file app/workers/good_morning_email_worker.rb
class GoodMorningEmailWorker
include Sidekiq::Worker
def perform
# send your emails
end
end
Then create a cron job from rails console to perform the worker every morning.
Sidekiq::Cron::Job.create(name: 'Email Worker - everyday #5am', cron: '0 5 * * *', class: 'GoodMorningEmailWorker')

Related

How to use Heya email campaigns with GoodJob instead of Sidekiq

I'm trying to send email campaigns in a rails app with the Heya gem and GoodJob. The example in the Heya readme as well as the Heya example app uses Sidekiq as the Active Job backend.
I'm confused about how to actually send the Heya campaigns with GoodJob.
The docs for Heya show this example of starting Sidekick: bundle exec sidekiq -q default -q heya
I assume that there is a Job queue somewhere in the gem called "Heya", but I can't find this in the source code. Do I need to create one?
Do I need to create a job that runs the Heya scheduler? While the example app uses Sidekiq, I also don't see any custom jobs in that app.
I have the following setup for GoodJob and it appears to be running fine with good_job start which should run all of the jobs and queues, but I've also tried good_job start --queues=heya,default.
Here is the relevant code:
Profile.dev
web: bin/rails server -p 3000
css: bin/rails tailwindcss:watch
worker: bundle exec good_job start
config/initializers/heya.rb
Heya.configure do |config|
config.user_type = "User"
config.campaigns.priority = [
"WelcomeCampaign",
]
end
app/jobs/application_job.rb
class ApplicationJob < ActiveJob::Base
# Automatically retry jobs that encountered a deadlock
# retry_on ActiveRecord::Deadlocked
# Most jobs are safe to ignore if the underlying records are no longer available
# discard_on ActiveJob::DeserializationError
end
app/campaigns/application_campaign.rb
class ApplicationCampaign < Heya::Campaigns::Base
segment :email_subscriber?
default from: "#{I18n.t('settings.site_name')} <#{I18n.t('settings.newsletter_email')}>"
end
app/campaigns/welcome_campaign.rb
class WelcomeCampaign < ApplicationCampaign
default wait: 5.minutes,
layout: "newsletter"
step :intro, wait: 0.minutes,
subject: "Welcome to #{I18n.t('settings.site_name')}"
end
I also have a layout and views for the campaign similar to the Heya example app, and I'm using Mailcatcher to see if any email is being sent.
What am I missing to send these emails with Heya and GoodJob?
Note that I'm subscribing the users on signups like this:
class User < ApplicationRecord
after_create_commit :add_user_to_newsletters
private
def add_user_to_newsletters
WelcomeCampaign.add(self)
EvergreenCampaign.add(self)
self.update(email_subscriber: true)
end
end
And the default segment in campaigns/application_campaign.rb is segment :email_subscriber?
If I run User.last.email_subscriber? in the console to check this it returns true.
I feel like I'm missing something about how Heya connects to Active Job that is not obvious in the Heya docs.
Also, not sure if this is related, but I added this to config/puma.rb
# https://github.com/bensheldon/good_job#execute-jobs-async--in-process
before_fork do
GoodJob.shutdown
end
on_worker_boot do
GoodJob.restart
end
on_worker_shutdown do
GoodJob.shutdown
end
MAIN_PID = Process.pid
at_exit do
GoodJob.shutdown if Process.pid == MAIN_PID
end
preload_app!
Are you running the heya scheduler periodically? $ rails heya:scheduler
It looks like you could create your own background job to be run using GoodJob Cron, by executing Heya::Campaigns::Scheduler.new.run to run the scheduler and enqueue the emails.
Reading the "Running the Scheduler" part of the README explains what's happening:
To start queuing emails, run the scheduler task periodically:
rails heya:scheduler
Heya uses ActiveJob to send emails in the background. Make sure your
ActiveJob backend is configured to process the heya queue. By default, GoodJob runs from all queues "*".
You can change Heya's default queue using the queue option:
# app/campaigns/application_campaign.rb
class ApplicationCampaign < Heya::Campaigns::Base
default queue: "custom"
end

In a Rails app running on multiple servers, how can I make sure a rake task runs only once?

I have a Rails app running on 2 servers in production.
I have a rake task that runs some import and then sends out an email to the users. I receive 2 emails now since there are 2 servers.
To avoid this, I tried creating a table my_import_run.
My import would check if a record with current date exists in the table, only if NOT the import would be run and email would be sent.
After sending email, all records in the table would be deleted and a record with only current date would be added
The above algorithm is implemented as shown here:
def self.import(search_date = Date.current)
if 0 == MyImportRun.count || !MyImportRun.where(:last_run => Date.today).any?
# the code to run import job and send email goes here
#
#
#
#
MyImportRun.delete_all
MyImportRun.new(:last_run => Date.today)
MyImportRun.save
end
But even after implementing the above code, I still receive 2 emails - I have no idea why. I was wondering maybe both the imports run at the exact same time and hence they both would find no records with current date and run import, send email and delete all records and add records with current date.
Is there a clean way of avoiding this from happening? The rake tasks would be automatically imported into cron job in Linux from what I understand; so I cannot delete the rake file from just one server.
Am sure there must be a clean way to avoid this duplication.
If you use Whenever and Capistrano that can be done with roles:
in a deploy file, you can set up a list of the roles:
server 'first-server', user: 'deployer', roles: %w{app db web sidekiq job}, primary: true
server 'second-server', user: 'deployer', roles: %w{app db web sidekiq job2}
and in the schedule.rb:
every 1.day, at: '5:00am', roles: [:job] do # this task will be run only on the first server
rake "-s sitemap:refresh:no_ping"
end
every 1.day, at: '5:00am', roles: [:job2] do # this only on second
rake "another_rake_task"
end
More details you can find this

How can I test sidekiq-scheduler in my local?

I am trying to add couple of scheduled workers to my rails application. These workers will be crawling different sites in given intervals.
I want to test these workers but not able to do it. I am starting redis and my application. What should I do to see whether my scheduled jobs are working or not?
Here is my crawler class:
class AyedasCrawler
include Sidekiq::Worker
and my sidekiq.yml is:
:schedule:
ayedas_crawler:
cron: '0 * * * * *' # Runs once per minute
class: AyedasCrawler
start the sidekiq worker and the scheduler processes by running
bundle exec sidekiq or sidekiq from your app root in the command-line.
sidekiq-scheduler provides an extension to the Sidekiq web interface that adds a Recurring Jobs page.
There are two ways to do this:
In your routes.rb file, just below the require 'sidekiq/web', add require 'sidekiq-scheduler/web'
In your config.ru, just below the require 'sidekiq/web', add
require 'sidekiq-scheduler/web'
run Sidekiq::Web
On the browser, goto ==> http://localhost:{port}/sidekiq/recurring-jobs. where {port} is the port your application is running in.
You will see the list of scheduled jobs for your application and some other details about it.
Read more in the official documentation
You need to run Sidekiq process as well.
bundle exec sidekiq
It will start both worker/s and the scheduler
If you wish to test it using rspec, you can to the following:
it 'spawns scheduled workers' do
Sidekiq::Cron::Job.load_from_hash YAML.load_file('config/sidekiq.yml')[: schedule]
Sidekiq::Cron::Job.all.each(&:enque!)
expect(AyedasCrawler.jobs.size).to be(1)
end
It loads the YAML configuration, enqueues all the jobs, and asserts if the job has been enqued.
Using this method you can validate if your schedule YAML is correct. It will NOT test CRON syntax and scheduled intervals.
I'm also using https://github.com/philostler/rspec-sidekiq to allow sidekiq testing without jobs actually being executed.

Rails: Testing Cron Jobs in development environment

I have a custom environment called 'reports' that is setup to hit a slave database. I am trying to configure some cron jobs using the Whenever gem and want to test them in development before I deploy. Is there any way to test cron jobs in development? Is there anyway I could schedule them locally and then start my reports server and see if they run? Thank You!
I would start off by reviewing how the gem itself (whenever gem) is conducting their tests. This is an extract from one of their functional test:
context "weekday at a (single) given time" do
setup do
#output = Whenever.cron \
<<-file
set :job_template, nil
every "weekday", :at => '5:02am' do
command "blahblah"
end
file
end
should "output the command using that time" do
assert_match '2 5 * * 1-5 blahblah', #output
end
end

Resque Scheduler plugin for the scheduled job not working

I am using this plugin for scheduled job.But it is not working.
I am confused about some points,Should I need to create the Job class and set their name in to schedule file?When testing it then,Should I run the rescue scheduler and Resque worker both or only one of them.
Thanks in advance.
My Resque Scheduler config... you will mostly need all these pieces:
YML file (config/resque_scheduler.yml):
every_1_minute:
cron: "* * * * *"
class: EveryMinute
queue: some_queue
description: Tasks to perform every minute
config/initializers/resque.rb:
require 'resque_scheduler'
Resque.schedule = YAML.load_file(File.join(Rails.root, 'config/resque_scheduler.yml'))
Ruby class (lib/every_minute.rb or somewhere in the load path):
class EveryMinute
def self.perform
puts "Hello every minute!"
end
end
You need to run
rake resque:scheduler
rake resque:work
The resque:scheduler process periodically queues up jobs, hence the scheduling. And the workers will just do the jobs blindly. This is why you need BOTH to successfully schedule and run jobs periodically.

Resources