I am creating an automatic raffling system. I have a draw button that will run a draw function to select a winner or winners and it sends an email to the admin.
I want this to be a completely automated system so that the admin only has to create the raffles and they receive an email with who won after the draw date has passed. My raffles have a draw date associated with them and once that passes, I need the function to be called.
How do I tell the application to check the time/date to see if any of the raffle draw times have passed? I have looked everywhere and cannot seem to find a way to do it.
You could use the whenever gem to define a job that runs hourly (or however often you want), checks the draw dates, and runs the draw for any that have passed.
I use Clockwork in my rails apps whenever I need to schedule things. Simply set it up to run a job when you want and do your logic within that job to see which raffles need to be processed. Example:
Clockwork config
every(1.day, 'Raffle::CheckJob', at: '01:00')
Job
Raffle.not_complete.find_each(batch_size: 10) do |raffle|
if raffle.has_ended?
// logic
end
end
You should write a rake task and add it's execution to your crontab on server. You can use whenever gem to simplify crontab scripting and auto update on each deploy (whenever-capistrano/whenever-mina). Example of your rake task:
namespace :raffle do
task :check do
Raffle.get_winners.each do |w|
Mailer.send_win_mail(w).deliver_later
end
end
end
deliver_later is background execution in queue by the queue driver you use (DelayedJob/Rescue/Backburner etc)
Related
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 want to schedule daily reports to subscribed users via email.
For that I have written action in reports_controller that fetch data from database & convert it into pdf using pdfkit/wkhtmltopdf.The action works fine when called from get request.But when converted so that be defined like
def self.dailymail
ac = ActionController::Base.new()
kit = PDFKit.new #retrieve data from db
pdf = kit.to_pdf
ReportMailer.send_reports(ac.send_data(pdf)).deliver
end
It raises exception at send_data call when used with rufus scheduler:
RackDelegation#content_type= delegated to #_response.content_type=, but #_response is nil: #<ActionController::Base:0x206b068 #_routes=nil, #_action_has_layout=true, #_headers={"Content-Type"=>"text/html"}, ...
so, my question is what how can I solve this problem or Is there any alternate scheduler in rails that work fair on both Windows and Linux?
I wish to know any scheduler that can be helpful to send reports fetched from database.
I agree with claasz regarding the rake task. Check out the whenever gem https://github.com/javan/whenever
There is no suport for windows Task Scheduler, but it does support creating cron jobs.
Check out the documentation for the details, but esentially the gem creates cron jobs based on what you configure in the schedule.rb file that is created when you install the gem.
sample content of schedule.rb:
every 3.hours do
runner "MyModel.some_process"
rake "my:rake:task"
command "/usr/bin/my_great_command"
end
This would be like running bundle exec rake my:rake:task every 3 hours
After creating the schedule.rb you will need to run the whenever command from the console in order to add your schedule to cron. If you run whenever without arguments, the output shows you the contents of the schedule.rb. There is an argument you need to provide that I can't remember off the top of my head, just pass --help and I think you'll get the answer.
Hope this helps
EDIT:The argument is -w to write to cron-tab
As willglynn already points out, you should get rid of any controller interaction. There's simply no need here and it makes things unnecessarily complicated. So your code should look more like
def self.dailymail
kit = PDFKit.new #retrieve data from db
pdf = kit.to_pdf
ReportMailer.send_reports(pdf).deliver
end
If you got problems with the rufus scheduler (which I don't know), you could create a rake task to send out your mails and use the OS scheduler (e.g. cron on Linux) to call the task. Having the rake task would be also convenient for testing.
I need to automatically change a record in my database on a specific date and time.
Example: When the date and time is 01/12/2012 17:15:00 I want some record to automatically be set to 1. Is there any solution to this?
(I am using Rails 3.2.6)
Update 30.11.12 - 13:06
The real problem is that I have a datetime record in my database, when the date and time in this record exceeds todays date and time - then I want another record to be set to 1. Is there any way I can make an if statement, or something, somewhere in my controller?
I can see a few possible options here. It depends on your assumptions/constraints.
Possible assumptions (ordered by increasing difficulty to implement):
1) the data does not need to be correct in the database, but the next time somebody takes a look at the data, we fix it accordingly
2) the data does not need to be correct in the database, but e.g. within a definable time-interval
3) the data needs to be correct in the database at all times
Let me go over these in more detail
The data will appear correct, next time somebody looks at the data
This is actually pretty easy. When retrieving the data to be shown, then check if certain conditions/times have past, and set flags accordingly.
For the user it is actually not relevant when the flags were set correctly, but everytime a user will look at the data, the flags will be set correctly.
The data will be correct inside a given time-interval
A simple case is to check every hour, every half hour, once per day and set or fix the states of items that need to be changed.
To accomplish this you would use a cron job or a gem like whenever
This is a very simple approach and will assure your data will be correct in an acceptable/given interval (if your problem has such an interval of course).
The data must be set at the correct time
Here I see two options, either for each item that needs to change state at a given time, schedule a
task using the same options as before: cron or the whenever gem. This would work, but I am not entirely sure if cron is the best solution for scheduling a lot of 1-off jobs.
Alternatively, a very clean solution is to use a gem like DelayedJob. This gem is mostly used to offload tasks to the background, e.g. for tasks that need a bit more time processin. But you can also use it to execute tasks in the near future, at a very specific time.
def change_flag_when_needed
# change the flag
end
# 5.minutes.from_now will be evaluated when change_flag_when_needed is called
handle_asynchronously :in_the_future, :run_at => Proc.new { 5.minutes.from_now }
Whenever you will call change_flag_when_needed, it will evaluate the given block, which now contains 5.minutes.from_now, but could as well calculate the actual time when it should be performed.
Hope this helps.
You could use whenever https://github.com/javan/whenever to set up a cron job for you
Whenever has an easy syntax in its schedule.rb file to let you run tasks "whenever" you like
From their readme:
every 3.hours do
runner "MyModel.some_process"
rake "my:rake:task"
command "/usr/bin/my_great_command"
end
every 1.day, :at => '4:30 am' do
runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
end
every :hour do # Many shortcuts available: :hour, :day, :month, :year, :reboot
runner "SomeModel.ladeeda"
end
every :sunday, :at => '12pm' do # Use any day of the week or :weekend, :weekday
runner "Task.do_something_great"
end
every '0 0 27-31 * *' do
command "echo 'you can use raw cron syntax too'"
end
# run this task only on servers with the :app role in Capistrano
# see Capistrano roles section below
every :day, :at => '12:20am', :roles => [:app] do
rake "app_server:task"
end
use cron job on linux server and set time for run script
I have a rails 3 application and looked around in the internet for daemons but didnt found the right for me..
I want a daemon which fetches data permanently (exchange courses) from a web resource and saves it to the database..
like:
while true
Model.update_attribte(:course, http::get.new("asdasd").response)
end
I've only seen cron like jobs, but they only run after a specific time... I want it permanently, depending on how long it takes to end the query...
Do you understand what i mean?
The gem light-daemon I wrote should work very well in your case.
http://rubygems.org/gems/light-daemon
You can write your code in a class which has a perform method, use a queue system like this and at application startup enqueue the job with Resque.enqueue(Updater).
Obviously the job won't end until the application is stopped, personally I don't like that, but if this is the requirement.
For this reason if you need to execute other tasks you should configure more than one worker process and optionally more than one queue.
If you can edit your requirements and find a trigger for the update mechanism the same approach still works, you only have to remove the while true loop
Sample class needed:
Class Updater
#queue = :endless_queue
def self.perform
while true
Model.update_attribute(:course, http::get.new("asdasd").response)
end
end
end
Finaly i found a cool solution for my problem:
I use the god gem -> http://god.rubyforge.org/
with a bash script (link) for starting / stopping a simple rake task (with an infinite loop in it).
Now it works fine and i have even some monitoring with god running that ensures that the rake task runs ok.
When a new resource is created and it needs to do some lengthy processing before the resource is ready, how do I send that processing away into the background where it won't hold up the current request or other traffic to my web-app?
in my model:
class User < ActiveRecord::Base
after_save :background_check
protected
def background_check
# check through a list of 10000000000001 mil different
# databases that takes approx one hour :)
if( check_for_record_in_www( self.username ) )
# code that is run after the 1 hour process is finished.
user.update_attribute( :has_record )
end
end
end
You should definitely check out the following Railscasts:
http://railscasts.com/episodes/127-rake-in-background
http://railscasts.com/episodes/128-starling-and-workling
http://railscasts.com/episodes/129-custom-daemon
http://railscasts.com/episodes/366-sidekiq
They explain how to run background processes in Rails in every possible way (with or without a queue ...)
I've just been experimenting with the 'delayed_job' gem because it works with the Heroku hosting platform and it was ridiculously easy to setup!!
Add gem to Gemfile, bundle install, rails g delayed_job, rake db:migrate
Then start a queue handler with;
RAILS_ENV=production script/delayed_job start
Where you have a method call which is your lengthy process i.e
company.send_mail_to_all_users
you change it to;
company.delay.send_mail_to_all_users
Check the full docs on github: https://github.com/collectiveidea/delayed_job
Start a separate process, which is probably most easily done with system, prepending a 'nohup' and appending an '&' to the end of the command you pass it. (Make sure the command is just one string argument, not a list of arguments.)
There are several reasons you want to do it this way, rather than, say, trying to use threads:
Ruby's threads can be a bit tricky when it comes to doing I/O; you have to take care that some things you do don't cause the entire process to block.
If you run a program with a different name, it's easily identifiable in 'ps', so you don't accidently think it's a FastCGI back-end gone wild or something, and kill it.
Really, the process you start should be "deamonized," see the Daemonize class for help.
you ideally want to use an existing background job server, rather than writing your own. these will typically let you submit a job and give it a unique key; you can then use the key to periodically query the jobserver for the status of your job without blocking your webapp. here is a nice roundup of the various options out there.
I like to use backgroundrb, its nice it allows you to communicate to it during long processes. So you can have status updates in your rails app
I think spawn is a great way to fork your process, do some processing in background, and show user just some confirmation that this processing was started.
What about:
def background_check
exec("script/runner check_for_record_in_www.rb #{self.username}") if fork == nil
end
The program "check_for_record_in_www.rb" will then run in another process and will have access to ActiveRecord, being able to access the database.