I found this Schedule one-time jobs in Rails
but this only shows how schedule one-time. I am interested in scheduling a recurring job.
Delayed_job has this
self.delay(:run_at => 1.minute.from_now)
How do I do something like that in Rails 4.2/Active Job?
Similar to rab3's answer, since ActiveJob has support for callbacks, I was thinking of doing something like
class MyJob < ActiveJob::Base
after_perform do |job|
# invoke another job at your time of choice
self.class.set(:wait => 10.minutes).perform_later(job.arguments.first)
end
def perform(the_argument)
# do your thing
end
end
activejob callbacks
If you want to delay the job execution to 10 minutes later, two options:
SomeJob.set(wait: 10.minutes).perform_later(record)
SomeJob.new(record).enqueue(wait: 10.minutes)
Delay to a specific moment from now use wait_until.
SomeJob.set(wait_until: Date.tomorrow.noon).perform_later(record)
SomeJob.new(record).enqueue(wait_until: Date.tomorrow.noon)
Details please refer to http://api.rubyonrails.org/classes/ActiveJob/Base.html.
For recurring jobs, you just put SomeJob.perform_now(record) in a cronjob (whenever).
If you use Heroku, just put SomeJob.perform_now(record) in a scheduled rake task. Please read more about scheduled rake task here: Heroku scheduler.
You can just re-enqueue the job at the end of the execution
class MyJob < ActiveJob::Base
RUN_EVERY = 1.hour
def perform
# do your thing
self.class.perform_later(wait: RUN_EVERY)
end
end
If you're using resque as your ActiveJob backend, you can use a combination of resque-scheduler's Scheduled Jobs and active_scheduler (https://github.com/JustinAiken/active_scheduler, which wraps the scheduled jobs to work properly with ActiveJob).
Related
I have a SchedulerJob:
class SchedulerJob < ActiveJob::Base
queue_as :scheduler
def perform
logger.debug("Start")
DelayedJob.set(wait: 10.seconds).perform_later
logger.debug("After Job 1")
DelayedJob.set(wait: 20.seconds).perform_later
logger.debug("After Job 2")
DelayedJob.set(wait: 30.seconds).perform_later
logger.debug("End")
end
end
and a DelayedJob:
class DelayedJob < ActiveJob::Base
queue_as :delayed_jobs
def perform
puts "I'm done"
end
end
If I call SchedulerJob.new.perform the job runs in just a few milliseconds. If I call SchedulerJob.perform_later to run the job in Sidekiq it takes about 90 seconds to finish, and by looking at the logs I can tell that each of those .perform_later calls takes about 30 seconds each.
Why would this happen?
By definition,
perform_later will be performed as soon as queuing system is free
perform will be performed regardless of your queue status
My guess is that when you call perform_later, there are some jobs running in the queue.
The problem was the initializer. This was the solution:
My guess is you’ve destroyed all concurrency by hacking in one global $REDIS connection into the pool. Don’t do that. Let Sidekiq create and manage the pool of connections.
I have some methods that works with API of third party app. To do it on button click is no problem, but it should be permanent process.
How to run them background? And how to pause the cycle for make some other works with same API and resume the cycle after the job is done.
Now I read about ActiveJob, but its has time dependences only...
UPDATE
I've tried to make it with whenever and sidekiq, task runs, but it do nothing. Where to look for logs I can't understand.
**schedule.rb**
every 1.minute do
runner "UpdateWorker.perform_async"
end
**update_worker.rb**
class UpdateWorker
include Sidekiq::Worker
include CommonMods
def perform
logger.info "Things are happening."
logger.debug "Here's some info: #{hash.inspect}"
myMethod
end
def myMethod
....
....
....
end
end
It's not exactly what I need, but better then nothing. Can somebody explain me with examples?
UPDATE 2 After manipulating with code it's absolutely necessary to restart sidekiq . With this problem is solved, but I'm not sure that this is the best way.
You can define a job which enqueues itself:
class MyJob < ActiveJob::Base
def perform(*args)
# Do something unless some flag is raised
ensure
self.class.set(wait: 1.hour).perform_later(*args)
end
end
There are several libraries to schedule jobs on a regular basis. For example you could use to sidekiq-cron to run a job every minute.
If you want to pause it for some time, you could set a flag somewhere (Redis/database/file) and skip execution as long it is detected.
On a somewhat related note: don't use sidetiq. It was really great but it's not maintained anymore and has incompatibilities to current Sidekiq versions.
Just enqueue next execution in ensure section after job completes after checking some flag that indicates that it should.
Also i recommend adding some delay there so that you don't end up with dead loop on some error inside job
I dont know ActiveJobs, but I can recommend the whenever gem to create cron (periodic background) jobs. Basically you end up writing a rake tasks. Like this:
desc 'send digest email'
task send_digest_email: :environment do
# ... set options if any
UserMailer.digest_email_update(options).deliver!
end
I never added a rake task to itself but for repeated processing you could do somehow like this (from answers to this specific question)
Rake::Task["send_digest_email"].execute
I have a worker like this:
class Worker
include Sidekiq::Worker
def perform
# ...
end
end
But there's something error with this worker, so I want to clear all jobs of it but don't want to clear jobs of other workers.
How can I implement this? Thanks.
Use the API to find and delete the jobs.
https://github.com/mperham/sidekiq/wiki/API#queue
I'm using Sidetiq and Sidekiq together to recurring jobs :
include Sidekiq::Worker
include Sidetiq::Schedulable
recurrence { secondly(3) }
def perform(id,last_occurrence)
# magic happens
end
However, now I want to stop the entire enqueuing process. I want to remove all the process from Sidetiq. How can I do?
Kind of late on this it looks like, but here we go anywho.
You can delete all scheduled sidetiq process like this:
Sidetiq::scheduled.each { |occurrence| occurrence.delete }
As far as preventing sidetiq from queuing additional jobs, i'm not sure how that works or how to dynamically stop it.
I need a cron job to write into my crontab that every after one minute calls a URL of rails application that triggers a method and runs a scheduled job.
I did not use whenever gem because it reboots the environment and i think it will strain my application. So i preferred to run a full system cron job independent of the rails app.
The URL to be called is https://xxxxxxxxx.com/scheduled_messages preferably being called using curl.
The controller being called is ;
class SchedulesController < ActionController::Base
def scheduled_messages
Schedule.scheduled_jobs
render nothing: true
end
end
and the method Schedule.scheduled_jobs is here;
def self.scheduled_jobs
jobs = Schedule.where('execution_time <= ?', Time.now)
if !jobs.empty?
jobs.each do |job|
task = Schedule.find(job)
MessageWorker.perform_async(task.message_id, task.lists, task.user_id)
task.destroy
end
end
end
While there are other ways to do this, the cron will look like:
* * * * * /usr/bin/curl "https://xxxxxxxxx.com/scheduled_messages".
One of those other ways could be rufus-scheduler.
Looks like you are using Sidekiq. Use Sidetiq for reccurring tasks. https://github.com/tobiassvn/sidetiq