I'm trying to use delayed_jobs (background workers) to process my incoming email.
class EmailProcessor
def initialize(email)
#raw_html = email.raw_html
#subject = email.subject
end
def process
do something with #raw_html & #subject
end
handle_asynchronously :process, :priority => 20
end
The problem is I can't pass instance variables (#raw_html & #subject) into delayed jobs. Delayed jobs requests that I save data into the model to be retrieved in the background task, but I would prefer to have a background worker complete the entire task (including saving the record).
Any thoughts?
Use delay to pass params to a method that you want to run in the background:
class EmailProcessor
def self.process(email)
# do something with the email
end
end
# Then somewhere down the line:
EmailProcessor.delay.process(email)
Related
When using Rails Action Mailer, you have the option to use deliver_now to send the email immediately, or deliver_later to send through asynchronously using Active Job. If Active Job is not specified an adapter, it will use an in-process thread pool which would not persist if the server were to stop. Alternatively, I can create a Job to manage my e-mails, which I can then call with perform_now or perform_later, which as I understand is more or less the exact same thing as deliver_now and deliver_later.
My question is, if I specify an adapter, let's say Sidekiq, and then have a database to store my jobs, why would I create a job to handle my e-mails? Is there any additional benefit, or is it an unnecessary step? On a slightly different note, if I did want to create a job for the process, would my email method need to have deliver_now or simply nothing at all? I presume if the e-mail were to say deliver_later, would it knock back the email to the end of the queue and force it wait again until it is sent?
To illustrate, if I have no Job set up to handle my emails, I could simply have:
class UserMailer < ActionMailer::Base
def send_email(user)
mail(to: user.email, subject: "My Subject")
end
end
To call, I would use:
UserMailer.send_email(my_user).deliver_later.
However, if I had wanted to add a job, and both options were called with UserJob.perform_later(user), would my setup be:
class UserJob < ActiveJob::Base
def perform(user)
UserMailer.send_email(user).deliver_now
end
end
Or
def perform(user)
UserMailer.send_email(user)
end
Lastly, I don't think this makes sense, but what would happen if I used:
def perform(user)
UserMailer.send_email(user).deliver_later
end
I'm trying to get the job which starts an action in this particular action.
Let me explain.
class MyClass
def go_for_it(delay = true)
if delay
delay(run_at: 2.minutes.from_now).go_for_it(false)
else
# How can I know if I was called by a DelayedJob AND if yes, which one ?
puts "I'll do it"
end
end
end
my_class = MyClass.new
my_class.delay(run_at: 2.minutes.from_now).go_for_it
My aim here is to make restrictions on jobs creation. I don't want go_for_it method called twice but this method can delay again itself according to some reasons. If I add those lines to go_for_it:
calling_method = caller_locations[0].label
job = Delayed::Job.where(queue: "my_queue").first
puts job.payload_object.id
# => id of MyClass if recorded
puts job.payload_object.method_name
# => :go_for_it
In the case of go_for_it delaying itself, these data are not enough because job variable can be itself and then it's not a second different call of got_for_it. It's just itself delayed again.
What I need to know here is which job call run or invoke_job on go_for_it method.
If I'm understanding well, you need to know which job is actually running.
You can use a custom job with a before hook to do an action before running the job, also you'll have totally access to job object at this moment.
Example :
class MyClassJob
def initialize(my_object: MyClass.new)
#my_object = my_object
end
def before(job)
binding.pry
another_job = Delayed::Job.where(queue: "my_queue").where('id <> ?', job.id)
end
def perform
#my_object.go_for_it
end
end
MyClassJob.new().delay.perform
I need to do a delayed job to count fbLikes in Model but I have the error report of "undefined send_later() method". Is there any way to do delayed job to my fb_likes function in model?
==============================Latest===================================================
This is my latest code in my project. Things still the same, fb_likes does not display likes count.
[Company.rb]-MODEL
require "delayed_job"
require "count_job.rb"
class Company < ActiveRecord::Base
before_save :fb_likes
def fb_likes
Delayed::Job.enqueue(CountJob.new(self.fbId))
end
end
[config/lib/count_job.rb]
class CountJob<Struct.new(:fbId)
def perform
uri = URI("http://graph.facebook.com/#{fbId}")
data = Net::HTTP.get(uri)
self.fbLikes = JSON.parse(data)['likes']
end
end
[controller]
def create
#company = Company.new(params[:company])
if #company.save!
flash[:success] = "New company successfully registered."
----and other more code----
Library files are not required by default.
Rename the job file to count_job.rb. Using camelCase for filenames is insane and will burn you in unpredictable ways.
Create an initializer and add require 'count_job.rb'
One way is to create a separate worker that will get queued, the run to fetch the updated Model and call its fb_likes method on it, but the method will need to be public. Or take the logic into the worker itself.
class Radar
include Mongoid::Document
after_save :post_on_facebook
private
def post_on_facebook
if self.user.settings.post_facebook
Delayed::Job.enqueue(::FacebookJob.new(self.user,self.body,url,self.title),0,self.active_from)
end
end
end
class FacebookJob < Struct.new(:user,:body,:url,:title)
include SocialPluginsHelper
def perform
facebook_client(user).publish_feed('', :message => body, :link => url, :name => title)
end
end
I want execute post_on_facebook method at specific date. I store this date at "active_from" field.
Code above is working and job is executed at correct date.
But in some cases I first create Radar object and send some job to Delayed Job queue. After that I update this object and send another job to Delayed Job.
This is wrong behavior because I wan't execute job only once at correct time. In this implementation I will have 2 jobs which will be executed. How I can delete previous job so only updated one will be executed ?
Rails 3.0.7
Delayed Job => 2.1.4 https://github.com/collectiveidea/delayed_job
ps: sorry for my english I try do my best
Sounds like you want to de-queue any jobs if a radar object gets updated and re-queue.
Delayed::Job.enqueue should return a Delayed::Job record, so you can grab the ID off of that and save it back onto the Radar record (create a field for it on radar document) so you can find it again later easily.
You should change it to a before_save so you don't enter an infinite loop of saving.
before_save :post_on_facebook
def post_on_facebook
if self.user.settings.post_facebook && self.valid?
# delete existing delayed_job if present
Delayed::Job.find(self.delayed_job_id).destroy if self.delayed_job_id
# enqueue job
dj = Delayed::Job.enqueue(
::FacebookJob.new(self.user,self.body,url,self.title),0,self.active_from
)
# save id of delayed job on radar record
self.delayed_job_id = dj.id
end
end
did you try storing the id from the delayed job and then store it for possible deletion:
e.g
job_id = Delayed::Job.enqueue(::FacebookJob.new(self.user,self.body,url,self.title),0,self.active_from)
job = Delayed::Job.find(job_id)
job.delete
I'm using delayed_job 2.1.4 from collectiveidea, and it seems the perform method is never called even though the jobs are processed and removed from the queue. Am I missing something?
I'm using Rails 3.0.5 on Heroku
In the Controller:
Delayed::Job.enqueue FacebookJob.new
In the Job class:
class FacebookJob
def initialize
end
def perform
fb_auths = Authentication.where(:provider => 'facebook')
fb_auths.each do |auth|
checkins = FbGraph::User.new('me', :access_token => URI.encode(auth.token)).checkins
if checkins != nil
checkins.each do |checkin|
[...]
end
end
end
end
end
(the whole code: https://gist.github.com/966509)
The simple answer: does DelayedJob know about the Authentication and FBGraph::User classes? If not, you'll see exactly the behavior you describe: the items will be silently removed from the queue.
See this entry in the Delayed Job Wiki in the Delayed Job Wiki.
Try adding 'require authentication' and 'require fb_graph' (or whatever) in your facebook_job.rb file.