I'm testing whenever to figure out how to use it and am running into trouble even after reading the Github documentation.
I simply want to update the attributes of my model like this (config/schedule.rb)
set :output "/log/today.log"
every 10.seconds do
runner "Example.update_all(sample: Time.now)"
end
I am neither seeing a log file nor seeing the model attributes updated.
Is there anything I am not doing correctly?
First you need to add your cron job in the cron tab.
If you do not want to add because you are just testing it, you can try the code given below(which i did for my rails application).
cd /home/your_home/your_project && script/your_script -e <environment> "method_call"
In your case:
environment = development
method_call = Example.update_all(sample: Time.now)
It might help you.
Related
I'm trying to understand how to use whenever properly, or if I'm even using it for the right thing. I've created a job:
class ScheduleSendNotificationsJob < ActiveJob::Base
queue_as :notification_emails
def perform(*args)
user_ids = User.
joins(:receipts).
where(receipts: {is_read: false}).
select('DISTINCT users.id').
map(&:id)
user_ids.each do |user_id|
SendNotificationsJob.create(id: user_id)
Rails.logger.info "Scheduled a job to send notifications to user #{user_id}"
end
end
end
I'd like to perform this job ever day at a set time. The job polls to see if there are any outstanding notifications, batches them, and then sends them to users so that a user can get one email with a bunch of notifications instead of a bunch of emails with one notification per email. I tried doing this with Delayed Job, but it seems it's not designed to schedule something on a recurring basis. So now I'm trying to do it with the whenever gem, but I can't seem to figure out how to set it up properly.
This is what I have in my config/schedule.rb file:
every 1.minute do
runner ScheduleSendNotifications.create
end
When I run whenever -i in the console I get the following:
Lorenzs-MacBook-Pro:Heartbeat-pods lorenzsell$ whenever -i
config/schedule.rb:13:in `block in initialize': uninitialized constant Whenever::JobList::ScheduleSendNotifications (NameError)
What am I doing wrong here? Should I be using something else? I'm just learning ruby and rails so any help is very much appreciated. Thank you.
The whenever gem takes a string as the argument to the runner function. Whenever doesn't actually load the Rails environment so it doesn't know about your ScheduleSendNotifications class.
The code below should get the crontab set up correctly to run your job.
every 1.minute do
runner "ScheduleSendNotifications.create"
end
From your project directory run whenever -w to set up the crontab file. Run crontab -l to view the written crontab file. Every minute the system will execute your Rails runner. From there you may need to debug your ScheduleSendNotifications.create code if something isn't working.
I want to execute a cron after creation of some entity every 2 minutes and I should be able to stop it through code only. Is it possible ?
For the simplest way that I can think of right now that you can do what #tlehman said and add a "checking flag" in the code. (maybe just a simple variable inside a filename)
so before the cron started, it should check for a file with X variable with value true/false.
if true then it should run the code, if false then exit.
(you could then write another code to modify that "check file" to enable/disable the cron)
That sounds like a job for the whenever gem, you can use it's simple DSL like so:
every 2.minutes do
runner "SomeRubyCommand.do_work"
end
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'm very new to rails and I have a script that I run from the console like this
$ ruby axml2xml.rb ExamPaper.apk
Now, how do I call this script from within my controller method and pass the same parameter as ExamPaper.apk?
I tried require 'axml2xml.rb' but got some error pointing to this line of code Zip::ZipFile.foreach(ARGV[0]) do |f|. So basically, how do I make something like axml2xml.rb 'ExamPaper.apk' in my controller?
You have at least 3 options:
exec(command)
%x{ command }
system(command)
They have different behaviors, so make sure to read this quicktip and/or the answer of this question to learn more about these commands.
In your case, the backticks or %x command is probably the best option.
value = `ruby axml2xml.rb ExamPaper.apk`
You can try using system or popen, but only for short tasks, for more information about that, please see here.
If your task is more time consuming you definitely should have a look at something like delayed_job and use a background job or some sort of queue to run your job. This way your server doesn't get blocked and your users do not have to wait til your job completes.
If you want to execute it as a shell command, use:
exec 'ruby axml2xml.rb ExamPaper.apk'
In ruby there are several ways to run shell commands.
system("ls")
%x("ls")
`ls` #nice they are back ticks
exec "ls"
But I'm not sure about the permissions necessary for running commands like that via rails.
I want to run a method, on the startup of the rails server. It's a model method.
I tried using config/initializers/myfile.rb, but the method was invoked during migrations, so it SELECTed from a nonexistant table.
Tried environment.rb also, but the class does not exist yet (and will probably have the same problem with migrations)
I don't know where to put that method, so it'll run only on server startup and not during migrations.
There are some things you could do to actually improve this a bit. The issue is that you are running this code when rake loads your environment, but you really only want to run this when the environment is loaded by an instance of your web server. One way to get around this is to set a value when rake loads your environment, and when that value is set, to not execute your initializer code. You can do this as follows:
task :environment => :disable_initializer
task :disable_initializer do
ENV['DISABLE_INITIALIZER_FROM_RAKE'] = 'true'
end
#In your initializer:
ENV['DISABLE_INITIALIZER_FROM_RAKE'] || MyModel.method_call
There is no way to avoid this from my understanding. You can put the initializer code that relies on the new table in a rescue block to quiet things down so others can run migrations.
Try putting your method call in boot.rb, in the run method after the Rails::initializer call. I don't have rails in front of me right now because I'm at work but I think that the whole environment should be loaded by that point and you can run methods on the framework.
I found this to work quite well:
if File.basename($0) == "rails" && ARGV == []
It also detects "rails generate .."