I would like to have a task that simply substracts a certain value from my user model at every 5 minutes.
My code:
schedule.rb
every 5.minutes do
runner 'Site::SubstractSomething.execute'
end
app/jobs/SubstractSomething.rb
module Site
class SubstractSomething
def initialize
end
def execute
#users = ::User.all
#users.each { |user| user.update_heat }
end
end
end
method inside user model:
def update_heat
self.heat -= 10
self.save
end
then I ran:
crontab -r
whenever --update-crontab --set environment='development'
EDIT:
I have taken out the job from the namespace and seems that it did the trick.Thanks for the help
You will have to require 'SubstractSomething' in your schedule.rb and make sure that your $LOAD_PATH includes the directory it is situated in. See this question for some possibilities on how to achieve this.
Related
I would like to launch a job which is going to calculate the points of each user of my web-App.
Here is the problem, I would like to launch it automatically with sidekiq-scheduler.
But I have trouble to understand how I can launch my job with an argument which is going to change. I mean I have to calculate the amount of points for each user, so the argument is going to change and take different user_id.
Here is my code :
class PointsjoueurJob < ApplicationJob
queue_as :default
def perform(user_id)
#user = User.find(user_id)
#playerseason = PlayerSeason.where(user_id: #user.id)
#forecasts = Forecast.where(player_season_id: #playerseason)
points = []
#forecasts.each do |forecast|
if forecast.points_win.present? || forecast.points_lose.present?
if forecast.points_win.present?
points << forecast.points_win
else forecast.points_lose.present?
points << forecast.points_lose
end
#playerseason.update(number_of_points: points.sum)
else
end
end
end
Right now if I want to launch it, I have to go to my console then type :
PointsjoueurJob.perform_now(1)
But I want to schedule this with sidekiq-scheduler. The goal is to trigger the work everyday at 01h00 (cron: '0 1 * * *')but I don't know how to set-up the argument in order for the job to iterate trough all the users.
Thank you by advance.
Assuming that you want to recalculate all users' totals, you can create a separate 'wrapper' job, which is scheduled, that in turn enqueues the individual recalculation jobs:
class RecalcPointsJob < ApplicationJob
queue_as :default
def perform
User.find_each do |u|
PointsjoueurJob.perform_later(u.id)
end
end
end
If you are after a subset of users instead, substitute User.where() or User.find_by().
You can generate a Task and use whenever, then setup it.
on task you can write this:
rails g task test cron
namespace :test do
task :cron do
User.find_each do |u|
PointsjoueurJob.perform_async(u.id)
end
end
end
then in config/schedule.rb after install whenever
every '0 1 * * *' do
rake "test:cron"
end
then
whenever --update-crontab
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 am new on cron jobs in Rails and I want to do it using 'whenever' gem. This is what I have tried so far.
Gemfile
gem 'whenever'
Mailer.rb
def new_test
Rails.logger.debug '===========whenever is working================'
end
Schedule.rb
every 1.minutes do
runner 'Mailers.new_test'
end
But this does not do anything. Where I am going wrong?
whenever actually does not automatically run that job for you. It is just an easy way for you to create corresponding cronjob on your system. You need to run the following command on your project to update your crontab
whenever -i
Regards
There seems to two error in your code :
in your scheduler.rb you are not calling mailer properly. You write Mailers.new_test it should be Mailer.new_test if Mailer is a simple model. And if it's mailer ie. override from class ActionMailer then it should be Mailer.new_test.deliver.
In case of Mailer is simple model then files should be :
Mailer.rb
new_test should be class method to call like Mailer.new_test not an instance method
def self.new_test # Should be a class method not instance
Rails.logger.debug '===========whenever is working================'
end
Schedule.rb
every 1.minutes do
runner 'Mailer.new_test'
end
And if mailer is instance of action mailer then :
Mailer.rb
def new_test
Rails.logger.debug '===========whenever is working================'
end
Schedule.rb
every 1.minutes do
runner 'Mailer.new_test.deliver'
end
I want the execution of a method in a controller to run in background, so that the speed is not affected. I found out that this could be done using delayed jobs.
following is the method I want to delay:
private
def update_product_count(skus, qty)
path = File.expand_path('../../../voylla_scripts/eBay', __FILE__)
system "python2 "+path+"/ReviseOnOrder.py #{skus.to_json} #{qty.to_json} #{path}> output"
end
I tried using:
def show
if defined? Delayed::Job
Delayed::Job.enqueue(update_product_count(#skus.to_s, #qty.to_s))
end
end
This runs the script within the delayed method, but gives error:
ArgumentError in OrdersController#show
Cannot enqueue items which do not respond to perform
and the view corresponding to the show does not get rendered.
then I tried:
def show
delay.update_product_count(#skus.to_s, #qty.to_s)
end
This doesn't run the method and also gives the following error:
ArgumentError in OrdersController#show
wrong number of arguments (1 for 0)
I also tried handle_asynchronously :update_product_count. But this too gives wrong number of arguments (1 for 0)
Could someone please help me figure this out. Thanks
EDIT: the following change does not give any error, but the script does seem to run
/lib/update_count.rb
class UpdateCount < Struct.new(:skus, :qty, :path)
def perform
system "python2 "+path+"/ReviseOnOrder.py #{skus.to_json} #{qty.to_json} #{path}"
end
end
/app/controller/order_controller.rb:
require 'update_count'
def show
Delayed::Job.enqueue(UpdateCount.new(#skus.to_s, #qty.to_s, path))
end
Place the code you want to execute in perform method, and enqueu the class in the delayed jobs, which when executed will call the perform method
Eg:
/lib/product_count.rb
class ProductCount < Struct.new(:skus, :qty)
def perform
path = File.expand_path('../../../voylla_scripts/eBay', __FILE__)
system "python2 "+path+"/ReviseOnOrder.py #{skus.to_json} #{qty.to_json} #{path}> output"
end
end
Call the delayed job
Delayed::Job.enqueue(ProductCount.new(#skus.to_s, #qty.to_s), :queue => "product_count")
You need to create a new class with public method "perform" which will incapsulate all job that you want:
class MegaJob
def initialize(options=nil)
#skus = options[:skus]
#qty = options[:qty]
end
def perform
update_product_count
end
private
def update_product_count
path = File.expand_path('../../../voylla_scripts/eBay', __FILE__)
system "python2 "+path+"/ReviseOnOrder.py #{#skus.to_json} #{#qty.to_json} #{path}> output"
end
end
To start this job:
Delayed::Job.enqueue MegaJob.new(skus: your_skus, qty: your_qty)
PS Don`t copy and paste the example!
Kinda embarrassing:
script/delayed_job start.
phew!!
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