Errors executing jobs with background job manager gem called Que - ruby-on-rails

I'm writing an Rails 4.2.0 application where I need to deliver emails. I've been advised Que gem for managing background jobs. I've done everything as in installation and usage is listed here.
Also I've specified in application.rb these lines:
# For https://github.com/chanks/que
config.active_record.schema_format = :sql
config.active_job.queue_adapter = :que
My job looks like this send_welcome_message.rb :
class SendWelcomeEmail < Que::Job
# Default settings for this job. These are optional - without them, jobs
# will default to priority 100 and run immediately.
#priority = 10
#run_at = proc { 1.minute.from_now }
def run(user_id, options)
#user = User.find(user_id)
UserMailer.welcome_email(#user).deliver_now
# Destroy the job.
destroy
end
end
After running the rails s command my console is populated with these messages:
{
"lib":"que",
"hostname":"...",
"pid":13938,
"thread":69925811873800,
"event":"job_unavailable"
}
And when I enqueue my job like this in controller
SendWelcomeEmail.enqueue 20, priority: 100
and refresh the page, I get the following errors all the time ( despite I can send messages is sync manner without using que ):
{
"lib":"que",
"hostname":"...",
"pid":13938,
"thread":69925811873800,
"event":"job_errored",
"error":{
"class":"ArgumentError",
"message":"wrong number of arguments (1 for 2)"
},
"job":{
"queue":"",
"priority":100,
"run_at":"2015-06-22T01:59:45.187+03:00",
"job_id":11,
"job_class":"SendWelcomeEmail",
"args":[
20
],
"error_count":2
}
}
And when I open rails console in the second terminal and enter there Que.worker_states (it's written here and should return information about every worker in the system) I get [].
I think that I have no workers spawned. Am I right? And how to fix it?
UPDATE
Found error in que log:
wrong number of arguments (1 for 2)
/home/username/train/project/app/jobs/send_welcome_email.rb:8:in `run'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/que-0.10.0/lib/que/job.rb:15:in `_run'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/que-0.10.0/lib/que/job.rb:99:in `block in work'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/que-0.10.0/lib/que/adapters/active_record.rb:5:in `block in checkout'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/connection_pool.rb:292:in `with_connection'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/que-0.10.0/lib/que/adapters/active_record.rb:34:in `checkout_activerecord_adapter'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/que-0.10.0/lib/que/adapters/active_record.rb:5:in `checkout'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/que-0.10.0/lib/que/job.rb:82:in `work'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/que-0.10.0/lib/que/worker.rb:78:in `block in work_loop'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/que-0.10.0/lib/que/worker.rb:73:in `loop'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/que-0.10.0/lib/que/worker.rb:73:in `work_loop'
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/que-0.10.0/lib/que/worker.rb:17:in `block in initialize'
Line 8 is:
def run(user_id, options)
SOLUTION
Now its' working. I've deleted the adapter configuration from application.rb and in place of
SendWelcomeEmail.enqueue 20, priority: 100
wrote
#user = User.find(20)
SendWelcomeEmail.enqueue #user.id, :priority => 100
Now it's works. Funny thing in the second variant the same values are passed to the function. Still error message said that run obtained only 1 argument - 20.

Reading the que gem, it looks like the enqueue method treats priority keyword as a special case: https://github.com/chanks/que/blob/master/lib/que/job.rb#L31
So, your run method is only passed the first argument. The priority keyword gets swallowed by que.
Changing your run method to
def run(user_id)
should fix your issue.

Related

STORYBLOK, RUBY: undefined method `[]' for nil:NilClass (NoMethodError)

I don't know that much about RUBY, just thought that you guys might help me with this. I'm using Storyblok as my headless CMS and JEKYLL when I'm building serve it this is the error that I got;
33: from C:/project/test/_plugins/storyblok_generator.rb:8:in `generate'
32: from C:/project/test/_plugins/storyblok_cms/generator.rb:12:in `generate!'
C:/project/test/vendor/cache/ruby/2.7.0/gems/storyblok-3.0.1/lib/storyblok/client.rb:354:in `block (2 levels) in find_and_fill_links': undefined method `[]' for nil:NilClass (NoMethodError)
the code below is from _plugins/storyblok_cms/generator.rb
def generate!
timestamp = Time.now.to_i
links = client.links(cv: timestamp)['data']['links']
stories = client.stories(per_page: 100, page: 1, cv: timestamp)['data']['stories'] #line 12
stories.each do |story|
# create all pages except global (header,footer,etc.)
content_type = story['content']['component']
if content_type != 'shared'
site.pages << create_page(site, story, links)
end
rescue UnknownContentTypeError => e
# for production, raise unknown content type error;
# for preview and other environments, issue an warning only since the content_type might be available
# but the code handling that content type might be in a different branch.
Jekyll.env == 'production' ? raise : Jekyll.logger.warn(e.message)
end
site.data['stories'] = stories
site.data['articles'] = stories.select { |story| story['full_slug'].start_with?('articles') }
site.data['shared'] = stories.select { |story| story['full_slug'].start_with?('shared') }
end
the code below is from _plugins/storyblok_generator.rb
require "storyblok"
module Jekyll
class StoryblokGenerator < Jekyll::Generator
safe true
def generate(site)
StoryblokCms::Generator.new(site).generate! #line 8
end
end
end
Additional Info:
ruby version: ruby 2.7.4p191 (2021-07-07 revision a21a3b7d23) [x64-mingw32]
jekyll version: jekyll 4.2.1
OS: Windows 10
I've actually found the solution to this, So this error occurs because I have created a page template in Block Library in Storyblok and then firing bundle exec jekyll serve command in terminal without creating the page template source/file in my project directory.
So I have an about_us block (content-type) in Block Library created and then when I fire bundle exec jekyll serve without creating an about_us.html first in _layouts folder, It would trigger the error.
Solution;
Make sure to create the source/file first in the _layouts folder if you have created a block (content-type) in block library.

Getting 'Use MyMailer.delay.mailer_action(args) to delay sending of emails.' error

I am getting an odd error: 'Use MyMailer.delay.mailer_action(args) to delay sending of emails.' but I can seem to find out where does it come from:
app/mailers/user_notifier.rb
class UserNotifier < ActionMailer::Base
default from: "test#testing.com"
def signup_email(user)
#user = user
mail(to: #user.email, subject: t("mailer.signup.subject"))
end
...
end
In Console, the non-delayed one works:
UserNotifier.signup_email(user).deliver
but when adding delay, error occurs:
UserNotifier.signup_email(user).delay.deliver
Rendered user_notifier/signup_email.html.erb (0.7ms)
RuntimeError: Use MyMailer.delay.mailer_action(args) to delay sending of emails.
from /Users/quindici/.rvm/gems/ruby-2.1.2/gems/delayed_job-4.0.6/lib/delayed/performable_mailer.rb:20:in `delay'
from (irb):6
from /Users/quindici/.rvm/gems/ruby-2.1.2/gems/railties-4.0.0/lib/rails/commands/console.rb:90:in `start'
from /Users/quindici/.rvm/gems/ruby-2.1.2/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in `start'
from /Users/quindici/.rvm/gems/ruby-2.1.2/gems/railties-4.0.0/lib/rails/commands.rb:64:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
It used to work but was broken sometimes ago. Still didn't get my head around it. Any idea would be much appreciated! Thank you.
When you use Delayed_job you'll can access .dealy method and then you can put the action mailer method like .deliver_later to delay sending of emails.
Simply way to add delayed_job in your project:
Add in your Gemfile:
gem "delayed_job_active_record"
gem "daemons"
Create the file "config/initializers/delayed_job_config.rb" with:
Delayed::Worker.destroy_failed_jobs = false
Delayed::Worker.sleep_delay = 60
Delayed::Worker.max_attempts = 3
Delayed::Worker.max_run_time = 5.minutes
Delayed::Worker.read_ahead = 10
Delayed::Worker.default_queue_name = 'default'
Delayed::Worker.delay_jobs = !Rails.env.test?
Delayed::Worker.raise_signal_exceptions = :term
Delayed::Worker.logger = Logger.new(File.join(Rails.root, 'log', 'delayed_job.log'))
In terminal:
$ bin/rails generate delayed_job:active_record
$ bin/rake db:migrate
$ bundle
$ bin/delayed_job start
Optional to view log: tail -f log/delayed_job.log
In some Mailer in your project (You can execute this in rails console):
SomeMailer.delay.some_method
Your queue will be processed in 60 seconds. You can remove the property Delayed::Worker.sleep_delay = 60 to process immediately.
Otherwise, you can configure your application to use delayed_job like your adapter for the active jobs and process works in background. Then you need to put config.active_job.queue_adapter = :delayed_job. This mode always you send an email you don't need to use .delay, instead, you call the mailer action and .deliver_later, for example: MyMailer.your_method.deliver_later. In this mode, the active job will enqueue the email in the delayed_job.
Questions and suggestions are welcome.
Reference: https://github.com/collectiveidea/delayed_job
I think you have it backwards:
UserNotifier.signup_email(user).delay.deliver
should be
UserNotifier.delay.signup_email(user)

Why do some rake tests fail with 'method_missing: private method location called for...'?

I'm upgrading a Rails 4.0 app to Rails 4.2. All the tests passed prior to the upgrade. However, I am now getting several errors (but no failures). This is the output of one of the tests:
Run options: --seed 30437
# Running:
E
Finished in 1.738307s, 0.5753 runs/s, 0.0000 assertions/s.
/opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/testing/assertions/routing.rb:171:in `method_missing': private method `location' called for #<[MyTestClass]:0xb46557c> (NoMethodError)
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/testing/integration.rb:397:in `method_missing'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest/test.rb:265:in `block in to_s'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest/test.rb:264:in `map'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest/test.rb:264:in `to_s'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:580:in `%'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:580:in `block in aggregated_results'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:579:in `each'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:579:in `each_with_index'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:579:in `each'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:579:in `map'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:579:in `aggregated_results'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:566:in `report'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:638:in `each'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:638:in `report'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:134:in `run'
from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:56:in `block in autorun'
I can't seem to find anything in my code that could be causing this error. Looking at some of the files mentioned in the stacktrace, it looks like it is erroring while trying to generate a failure message. (Double fail...)
What is the cause of this error?
Edit:
The first line of my test is s = login(:user). If I place a return before that line, the test passes, but if I place it after that line, I still get the error. The login function is defined in my test_helper.rb as follows:
def login(user)
open_session do |sess|
u = users(user)
sess.extend(MySession)
sess.get "/users/sign_in"
sess.assert_response :success
sess.post_via_redirect "/users/sign_in",
user: {
email: u.email,
password: "<password>"
}
assert_equal '/', sess.path
assert_equal "Signed in successfully.", sess.flash[:notice]
end
end
The module MySession contains a few helper methods.
Edit 2:
I opened a rails console session, required my test class, and did MyTestClass.private_methods. This was the output:
=> [:initialize, :_stash_object_in_method, :_superclass_delegating_accessor, :included, :extended, :prepended, :method_added, :method_removed, :method_undefined, :initialize_copy, :attr, :attr_reader, :attr_writer, :attr_accessor, :initialize_clone, :remove_const, :using, :remove_method, :undef_method, :alias_method, :public, :protected, :private, :define_method, :attr_internal_ivar_name, :attr_internal_define, :DelegateClass, :Digest, :timeout, :default_src_encoding, :Nokogiri, :irb_binding, :create_fixtures, :load, :require, :initialize_dup, :sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :warn, :raise, :fail, :global_variables, :__method__, :__callee__, :__dir__, :eval, :local_variables, :iterator?, :block_given?, :catch, :throw, :loop, :respond_to_missing?, :trace_var, :untrace_var, :at_exit, :syscall, :open, :printf, :print, :putc, :puts, :gets, :readline, :select, :readlines, :p, :srand, :rand, :trap, :require_relative, :proc, :lambda, :binding, :caller, :caller_locations, :exec, :fork, :exit!, :system, :spawn, :sleep, :exit, :abort, :Rational, :Complex, :set_trace_func, :gem_original_require, :Pathname, :URI, :rubygems_require, :BigDecimal, :j, :jj, :JSON, :not_implemented, :y, :open_uri_original_open, :pp, :singleton_method_added, :singleton_method_removed, :singleton_method_undefined, :method_missing]
Edit 3:
I opened a rails console session, required my test class, and did test = MyTestClass.new and then test.private_methods. This time, the output did contain :location. This app does have a Location model, and this output appeared in between several other of the app's models, so I suspect that is the problem. The question is now: why do my test classes have private methods named after my app's models? How can I fix or work around this problem? (Obviously I could rename the Location model, but I'd prefer to avoid that, if possible.)
Did the location method change from public to private on whatever class you're calling it on between Rails 4.0 and 4.2?
Maybe I'm misunderstanding, but the error seems pretty straightforward. Somewhere (in your code, or maybe a gem you rely on that's changed versions as well) a method called location is being called which is private. The stack track shows you where it's happening, so take a look at that code and see what's going on.
Might also be helpful to see the test code, but the stack trace is pointing you to the source from which you can trace back what's going on.
I looked through the code on github as well and can't find anything. Any chance you defined a method called location on MyTestClass that overrides the one in MiniTest::Test ? Also, if you go into your console and simply require the MyTestClass, and call .private_methods on it (or rather an instance of it), does :location indeed show up in the list? Any include statements anywhere that you can find in your code that might be bringing in a location method into MyTestClass?
It looks like this question/answer might provide a way to track down where these methods are coming from.
Using the .method and .source_location methods from #jefflunt's link, I was able to find the cause of the problem. When I did test.method(:location).source_location from the rails console, I got this output:
=> ["/opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-4.2.1/lib/active_record/fixtures.rb", 885]
When I looked up that line in that file, I found a method that defines private accessor methods for each fixture. Since I had fixtures defined for my Location model, that was the cause of this problem.
Since I don't see another way around this problem (aside from perhaps ditching fixtures, which I'm not ready to put time into just yet), I'll be renaming my Location model.

Why am I getting deadlocks? Using Thread, Queue, and ActiveRecord. Ruby 1.9.3, Rails 2.3.18

I mitigate the low success rate of a particular operation by running multiple threads and waiting for the first one to return with a valid answer. I've created a minimal example below:
THREADS = [] if !defined?(THREADS)
def threadtest
THREADS.clear
queue, mutex, result = Queue.new, Mutex.new, nil
10.times do |i|
THREADS << Thread.new do
counted = (10e6 + rand(10e6)).to_i.times { } # randomize computation time
num = rand(8) # succeed only 1/8 of the time
#mutex.synchronize do # even if wrapped in mutex
# print "#{User.last.inspect}\n" # deadlocks below if uncommented
#end
queue << [num, counted, i]
end
end
10.times do |i|
result, counted, num = queue.pop # deadlocks here
if result.zero?
puts "#{i}: #{num} succeeds after #{counted} counts"
break
elsif num.present?
puts "#{i}: #{num} failed with #{result} after #{counted} counts"
end
end
THREADS.each(&:exit)
return result
end
30.times { threadtest } # deadlock happens on "high load"
The error looks like:
fatal: deadlock detected
from /usr/lib/ruby/1.9.1/thread.rb:189:in `sleep'
from /usr/lib/ruby/1.9.1/thread.rb:189:in `block in pop'
from <internal:prelude>:10:in `synchronize'
from /usr/lib/ruby/1.9.1/thread.rb:184:in `pop'
from (irb):38:in `block in threadtest'
from (irb):37:in `times'
from (irb):37:in `threadtest'
from (irb):53:in `block in irb_binding'
from (irb):53:in `times'
from (irb):53
from /usr/local/bin/irb:12:in `<main>'
I've tried many variations in an attempt to prevent the deadlock, all to no avail. I can detail some of the experimentations I've done so far if requested. I do have one more idea that I've been avoiding due to the amount of refactoring it'd require in my application.
Is it simply the case that ActiveRecord can't be accessed via multiple threads?
I'll update with a few more details as I think of them.
'deadlock detected' error in rails is the the closest related question I found, but it's got no answers.
I had the same error and had to add the
gem 'net-ssh-gateway'
in the file Gemfile.lock, because the version that was bundled didn't work with the installed ruby. Seems like the dependency wasn't resolved any more in the newer ruby version.

New to Ruby trying to learn how to debug

I am migrating data from a database and getting an error I cannot understand. I am new to Ruby and am looking for both what is wrong with my code and also the most effective commands for debugging. I cannot even really read my error.
Here is my error:
/Users/skline/.rvm/gems/ruby-1.9.2-p136#rails3tutorial/gems/activemodel-3.0.6/lib/active_model/attribute_methods.rb:367:in `method_missing': undefined method `answer=' for #<Question:0x00000102d59758> (NoMethodError)
from /Users/skline/.rvm/gems/ruby-1.9.2-p136#rails3tutorial/gems/activerecord-3.0.6/lib/active_record/attribute_methods.rb:46:in `method_missing'
from ./script/migrate.rb:139:in `block (2 levels) in <main>'
from /Users/skline/.rvm/gems/ruby-1.9.2-p136#rails3tutorial/gems/activerecord-3.0.6/lib/active_record/relation.rb:13:in `each'
from /Users/skline/.rvm/gems/ruby-1.9.2-p136#rails3tutorial/gems/activerecord-3.0.6/lib/active_record/relation.rb:13:in `each'
from ./script/migrate.rb:137:in `block in <main>'
from ./script/migrate.rb:111:in `each'
from ./script/migrate.rb:111:in `<main>'
Any tips for reading this error and for how to debug.
Note here is my code:
NetworkCommunications.all.each do |nc|
if nc.NETWORK_COMM_TYPE_ID==1 && nc.SENDER_CONSUMER_ID != 0
q = Question.new
q.created_at = nc.LAST_MOD_TIME
category = CommunicationInterestMapping.where(:COMMUNICATION_ID => nc.COMMUNICATIONS_ID).first
if category
cie = ConsumerInterestExpertLookup.find(category.CONSUMER_INTEREST_EXPERT_ID)
if cie
q.category = Category.find_by_name cie.CONSUMER_INTEREST_EXPERT_NAME
else
puts "No category"
end
end
message = NetworkCommunicationsMessage.where(:COMMUNICATIONS_ID => nc.COMMUNICATIONS_ID).first
q.title = message.SUBJECT
q.description = message.MESSAGE
q.permalink = message.QUESTION_SLUG
email = find_email_from_consumer_id(nc.SENDER_CONSUMER_ID)
q.user = User.find_by_email email
children = NetworkCommunications.where(:PARENT_COMMUNICATIONS_ID => nc.COMMUNICATIONS_ID)
puts children
if children
children.each do |ncc|
if ncc.NETWORK_COMM_TYPE_ID == 2
q.answer = Answer.new
q.answer.created_at = ncc.LAST_MOD_TIME
message_a = NetworkCommunicationsMessage.where(:COMMUNICATIONS_ID => ncc.COMMUNICATIONS_ID).first
q.answer.text = message_a.MESSAGE
email_a = find_email_from_consumer_id(ncc.SENDER_CONSUMER_ID)
q.answer.user = User.find_by_email email_a
end
end
end
begin
q.save!
rescue Exception => e
puts "Exception: #{e} title: #{message.SUBJECT}"
end
end
end
To read the stack dump, look at the first line then read downwards:
/Users/skline/.rvm/gems/ruby-1.9.2-p136#rails3tutorial/gems/activemodel-3.0.6/lib/active_model/attribute_methods.rb:367:in `method_missing': undefined method `answer=' for #<Question:0x00000102d59758> (NoMethodError)
from /Users/skline/.rvm/gems/ruby-1.9.2-p136#rails3tutorial/gems/activerecord-3.0.6/lib/active_record/attribute_methods.rb:46:in `method_missing'
from ./script/migrate.rb:139:in `block (2 levels) in <main>'
The first line tells you where the problem was triggered and why: In ActiveModel's attribute_methods method because no setter for answer was found in the object. This was triggered from a call in line 139 of your migrate.rb script. The trick with a stack trace is to read through it, looking for the scripts you've written. Odds are really good the problem is in our code so it's always good to start from the assumption the bug is ours.
if ncc.NETWORK_COMM_TYPE_ID == 2
q.answer = Answer.new
is where the problem is. Your Question class doesn't have a setter for answer. Either you're missing or misspelled an attribute_accessor call or misspelled a def answer= method.
To debug I recommend using Ruby Debugger 1.9. gem install ruby-debug19. It's 1.9.2 studly and easy to use. You can set a breakpoint in your code, then run it from the command-line, which will run until the breakpoint is reached and will stop in the debugger. From there you can list the current lines using l, display the contents of variables using p or do a require 'pp' if you have pretty-printer installed. You can single-step into methods using s or step over them using n, for "next". There's also c to continue, c 100 to continue to a particular line number; 100 in that example. You can use b 100 to set a break-point at line 100, and then c to run, stopping at 100 every time. irb will drop you into IRB with the variables to that point already initialized so you can poke at them. There are lots of other commands, but those are the ones I use most often.
It probably means you have defined the answer attribute for your question class:
class Question < ActiveRecord::Base
attr_accessor :answer
[...]
end
You should also learn how to use rdebug so that you can step through the code and figure this out without help.
I think your model Question doesn't have answer attribute.
In this cast you can study how to debug rails app

Resources