I'm new to Delayed Jobs and am not sure if I'm doing this correctly.
Worker
class BillingFailedEmailWorker < BaseWorker
attr_accessor :car
def initialize(car)
#car = car
end
def billing_failed_for_subscriptions
StripeMailer::billing_failed_for_subscriptions(car.owner.email).deliver
end
def perform
self.class.new(car).delay(
run_at: DateTime.now + 1.week,
queue: "Failed Subscription"
).billing_failed_for_subscriptions
end
end
Mailer
class StripeMailer < ActionMailer::Base
default from: Settings.default_from_email
def billing_failed_for_subscriptions(email)
mail to: email, subject: 'Autobrain Subscription Renewal Failed'
end
end
billing_failed_for_subscriptions also obviously corresponds to the correct mailer view.
My question is when I run BillingFailedEmailWorker.new(Car.last).perform I see the command execute correctly in Delayed::Backend::ActiveRecord::Job but when I run Delayed::Backend::ActiveRecord::Job.last or Delayed::Job.last I don't see the job I just created.
Could this be a matter of my Rails environment being in development or is there something I'm missing?
Instead of using
StripeMailer::billing_failed_for_subscriptions(car.owner.email).deliver
use
StripeMailer::billing_failed_for_subscriptions(car.owner.email).deliver_later
Then in the console you can check it as Delayed::Job.last
Related
I would like to automate a task in my Rails app, create a rake task, almost all the code I need is in a controller action, I would like to just call that controller action instead of write the "same" code in my task and save some lines of code. Is that possible?
Well, for example. Say you have usecase to auto renew Stripe customers subscriptions from both Rake tasks and using client side . Now, you will write a PORO class like below:
class AutoRenewSubscription
attr_reader :coupon, :email
def initialize args = {}
#email = args[:email]
#coupon = args[:coupon]
#....
end
def run!
user_current_plan.toggle!(:auto_renew)
case action
when :resume
resume_subscription
when :cancel
cancel_subscription
end
end
#... some more code as you need.
end
You can put the class inside app/services/auto_renew_subscription.rb folder. Now this class is available globally. So, call it inside the controller like :
class SubscriptionController < ApplicationController
def create
#.. some logic
AutoRenewSubscription.new(
coupon: "VXTYRE", email: 'some#email.com'
).run!
end
end
And do call it from your rake task also :
desc "This task is to auto renew user subscriptions"
task :auto_renew => :environment do
puts "auto renew."
AutoRenewSubscription.new(
coupon: "VXTYRE", email: 'some#email.com'
).run!
end
This is what I think good way to solve your issue. Hope you will like my idea. :)
i am new in ROR and i am using 'Sidekiq' for scheduling Reminders. i can schedule reminder jobs/messages successfully through "Sidekiq". Here is code of 'reminder.rb'
class Reminder < ActiveRecord::Base
belongs_to :user
belongs_to :status_value
belongs_to :communication
after_create :add_sidekiq_job
# before_destroy :remove_sidekiq_job
def add_sidekiq_job
id = ReminderWorker.perform_at(scheduled_at, {id: self.id.to_s})
# self.update_attributes(job_id: id)
end
def remove_sidekiq_job
queue = Sidekiq::ScheduledSet.new
job = queue.find_job(self.job_id)
job.delete if job
end
def scheduled_at
self.notification_time.to_time.to_i - Time.now.to_i
end
end
and here is code of 'reminderworker.rb' where i can get 'reminder/notification message' by passing the id.
class ReminderWorker
include Sidekiq::Worker
def perform(args)
reminder = Reminder.find(args['id'])
puts "~~~~~Notificaiton~~~~~~~~"
end
end
Everything is working till now but now i want to show notification message (which i can get from 'reminder = Reminder.find(args['id'])') in my notification page . how i can do this?
If you want to show this message on user's page you should use some kind of persisted pub/sub client-server connection, that will be available in sidekiq. In Rails 5 it could be ActionCable, in previous versions of Rails - Faye or something like this.
I have using Rails + DelayedJob Mongoid. I have this model:
class User
def run
...
end
end
I create new Dejayed::Job object:
user = Use.create
user.delay.run
How I can I do something like this?
Delajed::Job.where(object_id: user.id)
I am not sure if this will work in your case.
If you have the delayed_job object id, you can simply find it like normal activerecord objects.
# find a job by id
job = Delayed::Job.find(params[:id])
Now when you dont have the id. Then add something unique during the creation of the job itself
in users_controller.rb
user = User.create
in user.rb
def delayed_run
my_job = MyJob.new('xyz')
job = Delayed::Job.enqueue(run, 0, 1.hour.from_now)
job.user_id = self.id
end
So after this, you can find your delayed job object from the unique user_id
Delayed::Job.where(user_id: 5)
Based on #aelor answer, finally I had to add field object_id to Job class:
# config/initializers/dejayed_job.rb
module Delayed
module Backend
module Mongoid
class Job
include ::Mongoid::Document
field :object_id
end
end
end
end
Then it works ok:
user = Use.create
user.delay(object_id: user.id).run
Delayed::Job.where(object_id: 5).first
=> #<Delayed::Backend::Mongoid::Job _id: 551a5116726a750e08000000
I'm attempting to use the whenever to execute a method every 30 minutes. However I'm having some trouble setting it up.
schedule.rb
every 1.minutes do
runner "Post.winner"
end
post.rb
class Post < ActiveRecord::Base
module Post
def winner
#do some stuff that saves a new value in database
I don't think the runner is working because the field that I save a value to still shows up as nil in the console.
You most probably do not want to run a controller method (eg you have no request to serve there). Either create a runner from a class or module.
# schedule.rb
every 30.minutes do
runner "Post.winner"
end
#lib/post.rb
module Post
def self.winner
...
end
end
or a rake task in lib/tasks/
# schedule.rb
every 30.minutes do
rake post:winner
end
#lib/tasks/post.rake
namespace :post do
desc 'calculate winner'
task :winner do
...
end
end
I'm almost sure you have a model Post. Create a class method:
class Post
...
def self.winner
...
end
end
But if you are using Post.winner only for the schedule, I prefer a rake task as #xlembouras suggested.
I'm using resque to do some (long time) job. And I have a few classes with the same mixed-in module for queuing. Class Service substitutes in tests, that's why it standalone and (maybe too much) complicated. So the story is when I call
Campaign.perform(user_id)
directly, everything works fine, but when I try to use queue:
Resque.enqueue(Campaign, user_id)
Job created, but seems like do nothing. At least, nothing saves into the database. Which is main task of Campaign class. I can see in resque-web-interface that jobs creates and finished, and finished (to fast, almost just after create) but no result.
I'm new in Resque and not really sure it calls it all (confused how to debug it).
Does anybody have similar problem? thanks for any help.
Module:
module Synchronisable
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def perform(user_id)
save_objects("#{self.name}::Service".constantize.get_objects(user_id))
end
protected
def save_objects(objects)
raise ArgumentError "should be implemented"
end
end
class Service
def self.get_objects(user)
raise ArgumentError "should be implemented"
end
end
end
One of the classes:
class Campaign < ActiveRecord::Base
include Synchronisable
#queue = :app
class << self
protected
def save_objects(objects)
#some stuff to save objects
end
end
class Service
def self.get_objects(user_id)
#some stuff to get objects
end
end
end
This is a very old question so not sure how rails folder structure was back then but I had the same problem and issue was with inheritance. Seems if you are using Resque your job classes shouldn't inherit from ApplicationJob.
so if your code was like this in (app/jobs/campaign_job.rb):
class Campaign < ApplicationJob
#queue = :a_job_queue
def self.perform
#some background job
end
end
then remove the inheritance i.e "< ApplicationJob"
These jobs are almost certainly failing, due to an Exception. What is resque-web showing you on the Failures tab? You can also get this from the Rails console with:
Resque.info
or
Resque::Failure.all(0)
You should run your worker like this:
nohup QUEUE=* rake resque:work & &> log/resque_worker_QUEUE.log
This will output everything you debug to "log/resque_worker_QUEUE.log" and you will be able to find out what's wrong with your Campaign class.
Try this:
env TERM_CHILD=1 COUNT=2 "QUEUE=*" bundle exec rake resque:workers