Calling class method within rake task, nothing happening - ruby

So I have a class method which works great for my ApplicationMailer. It finds orders that are not fulfilled, converts them to CSV, attaches them in an email, and emails them to a predefined email address.
This is working fantastically.
However, when I call this method in a rake task, it does absolutely nothing. This is the first rake task I have written and am trying to use it with heroku scheduler to send out orders to be fulfilled every night.
the code for my rake task is below:
desc "send daily orders to shipping"
task :send_orders_to_shipping => :environment do
ApplicationMailer.email_days_orders
end
This rake task shows up in rake -vT as rake send_orders_to_shipping but when I call "bundle exec rake send_orders_to_shipping", the command line seems to pause for 5-10 seconds, like its doing something, but no error is passed back or anything and nothing happens. No orders are marked as fulfilled in the database as they are when I simply run the class method from the command line and no emails are sent.
Any help is appreciated, I am new to rake and am wondering if I have missed something in my reading?
I was instructed to put the :environment block by herokus documentation for using the scheduler addon. Could this be messing things up?
edit: here is the code for ApplicationMailer.email_days_order which works from the command line.
def email_days_orders
ordlength = Order.where(fulfilled: false).length
indordlength = Individualorder.where(fulfilled: false).length
if ordlength > 0
attachments["school_orders_#{Date.today}.csv"] = Order.todays_orders_to_csv
end
if indordlength > 0
attachments["individual_orders_#{Date.today}.csv"] =
Individualorder.todays_indorders_to_csv
end
if ordlength > 0 || indordlength > 0
mail(to: [ENV['SHIPPING_EMAIL_1'], ENV['SHIPPING_EMAIL_2'],
ENV['SHIPPING_EMAIL_3']] ).deliver
end
end

You're forgetting to actually send the email. Try ApplicationMailer.email_days_orders.deliver_later (or .deliver_now)

Related

Running resque without Rakefile

I have built my own job server, which is essentially a private gem, built as a wrapper around resque.
(I am not running this in a Rails environment)
Everywhere I look, it seems like the documented/recommended way to start the workers, is with something like this:
$ QUEUE=* rake resque:work
Which means that it must be executed in a folder where the Rakefile exists.
I am looking for a way to start it without a Rakefile.
What I have learned so far:
I have looked through the issues, maybe someone asked a similar question.
I have looked through the wiki, and specifically the FAQ.
I know I can probably create my own "bin" to run it without rake, by analyzing the tasks file.
I saw that resque installs a resque binary, but it only seems to provide limited functionality, like removing and listing a worker, but not starting.
My current workaround is that my gem's binary is doing chdir to the gem's folder before running (and this folder has a Rakefile), like the code below.
def start_worker
ENV['QUEUE'] = '*'
Dir.chdir gemdir do
exec "rake resque:work"
end
end
def gemdir
File.expand_path "../../", __dir__
end
Appreciate any nudge in the right direction.
The current solution I have worked up for this:
def start_worker
interval = 5
queue = '*'
ENV['QUEUE'] = queue
worker = Resque::Worker.new
Resque.logger = Logger.new STDOUT
Resque.logger.level = Logger::INFO
## this is not yet implemented in 1.26.0, keeping here as a reminder
# worker.prepare
worker.log "Starting worker"
worker.work interval
end
Which is an adaptation of the code from the rake task
For reference, I also opened a github issue, in the off chance that someone else also needs such functionality.
I having created a script to create demon worker processes using following worker starting API.
def start_worker(id)
ENV['QUEUE'] = #queues || "*"
ENV['PIDFILE'] = pid_file(id)
ENV['JOBS_PER_FORK'] = #jobs_per_fork || "1000"
ENV['BACKGROUND'] = 'true'
ENV['TERM_CHILD'] = 'true'
#debug ? ENV['VVERBOSE'] = 'true' : ENV['VERBOSE'] = 'true'
begin
worker = Resque::Worker.new
rescue Resque::NoQueueError
Resque.logger.error "No queue is set for worker_id = #{id}"
end
worker.prepare
worker.log "Starting worker #{self}"
worker.work(5) # interval, will block
end

Resque tasks always fail - uninitialized job constants?

I've tried using Resque before and was met with unmitigated failure. I'm revisiting it again with the same results...
resque.rake:
require "resque/tasks"
task "resque:setup" => :environment
test.rb:
require 'resque'
class FileWorker
#queue = :save_to_file
def self.perform(str)
File.open('./' + Time.now.to_s + '.txt', 'w+') do |f|
f << "test 123"
end
end
end
Resque.enqueue(FileWorker, "12345567".split('').shuffle.join)
Gemfile:
gem 'resque'
gem 'rake'
It seems like running test.rb on its own successfully queues the job:
However, running rake resque:work QUEUE='*' in the same folder results in a warning,
WARNING: This way of doing signal handling is now deprecated. Please
see http://hone.heroku.com/resque/2012/08/21/resque-signals.html for
more info.
As well as the task being added to "failed" queue with the following reason: "exception":"NameError","error":"uninitialized constant FileWorker"
How do I get this to work? Seems like something quite obvious but there's tons of tutorials about Resque spanning many years - some painfully out of date and none explaining how to run workers so they don't fail.
Thanks in advance.
When you enqueue a task with Resque, what is stored on Redis is just the name of the job class (as a string) along with the arguments (again as strings) in a JSON object.
When a worker then tries to perform the task, it needs to be able to create an instance of the job class. It does this by using const_get and const_missing. This is where the error you are seeing occurs, since the worker does not have the definition of FileWorker available to it.
The error is the same as if you tried to get an unknown constant in irb:
> Object.const_missing "FileWorker"
NameError: uninitialized constant FileWorker
The solution is to make sure the definition of FileWorker is available to your workers. The simplest way to do this would be to just require test.rb from your Rakefile (or resque.rake). In your code this would involve adding another task to the queue, so you might want to move the FileWorker code to its own file where it can be required by both the rake file and the code enqueuing jobs.
test.rb:
require 'resque'
require './file_worker'
Resque.enqueue(FileWorker, "12345567".split('').shuffle.join)
Rakefile (note the :environment task only makes sense if you are using Rails and will give errors otherwise):
require "resque/tasks"
require "./file_worker"
file_worker.rb:
class FileWorker
#queue = :save_to_file
def self.perform(str)
File.open('./' + Time.now.to_s + '.txt', 'w+') do |f|
f << "test 123"
end
end
end
Now the workers will be able to create instances of FileWorker to complete the tasks.
The way to avoid the warning about signals is given in the page linked to in the message. Simply set the environment variable TERM_CHILD when calling rake:
$ rake resque:work QUEUE='*' TERM_CHILD=1

Rake task return value for Ruby system() call

I have a Rake task which looks something like the following. What I’m trying to do run a system command, and return its error-value. Before returning I’d like to display a message saying something like “[OK]” or “[FAILED]".
With this code, Rake returns success every time.
How do I get the Rake task to return the correct error value?
task :build do
status = system BUILD_SHELL_COMMAND
puts status ? "[OK]" : "[FAILED]"
status
end
It appears there isn’t a way to specify a “return value” from a rake task. The task should fail if the system() method fails.
The standard way to do this would be to use Rake’s sh utility method:
task :build do
sh BUILD_SHELL_COMMAND
end
To display an error/success message however, for the case in question, the following would not work:
task :build do
sh BUILD_SHELL_COMMAND or fail “[FAILED]”
puts “[OK]"
end
because as soon as the shell command fails, it would not display the failure message (which in reality would be a longer non-trivial message :), which is what we want.
This works:
task :build do
system BUILD_SHELL_COMMAND or fail “[FAILED]”
puts “[OK]"
end

How to get the pid for the first task with the Daemons gem?

I am trying to run multiple instances of the same code/script using the Daemons gem. I've been playing around with it in an IRB session and can't seem to get the functionality I'm looking for. I want to run the same script multiple times keeping track of the PID so that I can manually start and stop processes. More specifically, I have a rails model whose instance will control a single process and so I will need to start and stop it using something like
mydaemon = MyDaemon.create
mydaemon.start # starts the process
mydaemon.stop # stops the process
However, in order to achieve something like this I wanted to store the PIDs for the process in active record. When I run the following code in IRB:
require 'rubygems' # if you use RubyGems
require 'daemons'
task1 = Daemons.call(:multiple => true) do
loop {
File.open("/tmp/daemon_test.log", "w") {|f| f.write(Time.now.to_s + "\n")}
sleep 5
}
end
the task automatically starts (without ever calling start on task1), and instead of returning the pid, it returns the Daemons::Application object associated with task1. I only have access to the pid when I start a second instance of task1 i.e.:
task1.start
=> 574 # PID of process but now I have 2 proc's running, one of which I don't know the PID of
Am I using Daemons wrong? or is there no way to get the PID of the very first process that starts automatically when calling Daemons.call?
Thanks,
Tomek
The docs say that an Daemons::Application object has a public attribute pid which returns a Daemons::Pid object, so try using that task1.pid.pid.

How do I launch multiple rakes in parallel from a ruby script

I have a ruby script from which I want to launch 4 rake tasks to run in parallel.
How do I do this? I think I'll need to Fork and detach a process but I need the exact syntax.
It's better if you let Rake handle the parallelism. You can do that using "multitask." Inside the Rakefile:
desc "Start everything."
multitask :start => [ 'mongodb:start', 'haystack:start' ]
Background and source.
Otherwise, presuming you are doing this from outside the Rakefile, you could use horrid code like this, which would not throw exceptions as you might expect, and could easily fail in a number of ways:
require 'rake'
load 'Rakefile'
def invoke(name)
Thread.new do
puts Rake::application[name].invoke
end
end
invoke :make_coffee
invoke :boil_eggs
invoke :empty_trash
(so don't do that)
use https://github.com/grosser/parallel
Parallel.each(data, :in_processes => 4) { |x| ruby_function(x) }
You can try to use Multithreading:
http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_threads.html
also here was discussion on SO:
Running multiple background parallel jobs with Rails
make has a similar feature (-j) which allows you to run multiple tasks in parallel.
there is a pull request open to have this feature available in rake:
https://github.com/jimweirich/rake/pull/113
and a fork of rake with -j implemented:
https://github.com/quix/rake

Resources