I've got a delayed job running and I want to saved the runtime when it finishes, the worker logs the runtime to the logs like this...
XXXXXJob completed after 1.6372
I was wondering how you access this statistic from inside the delayed job class?
I've tried self.runtime but that's throwing an error.
Cheers.
I'm afraid delayed_job gem doesn't provide API for accessing that stats. Looks like here is the place were they calculate running time and that's what is happening there:
runtime = Benchmark.realtime do
invoke_job
destroy
end
logger.info "* [JOB] #{name} completed after %.4f" % runtime
So runtime is calculated using Benchmark module and logged, but it's not stored anywhere for later usage.
Though, you still can calculate runtime of the job yourself by wrapping its logic with similar Benchmark.realtime call or something like that.
Related
My counter cache is locking the row under heavy load so I found wanelo/counter-cache gem which seems to be perfect for my problem but I can't set it up and it must be something really simple but I can't see it.
https://github.com/wanelo/counter-cache
I want it to use my already working delayed jobs and Redis.
In my config file
Counter::Cache.configure do |c|
c.default_worker_adapter = here??? DelayedJob ??
c.recalculation_delay = 5.hours
c.redis_pool = Redis.new
c.counting_data_store = Counter::Cache::Redis
end
If I don't put the line c.default_worker_adapter when executing it says
undefined method 'enqueue' for nil:NilClass
Any idea on what's going on? What should I put in the Worker Adapter? Nothing seems to work.
Thank you for your time
default_worker_adapter is the name of the class that will be handling your updates. An example is given on the github page of the gem. For example if you're using sidekiq, you would make sidekiq worker class and name it whatever you want. On the github page, this class is called CounterWorker and you can copy it exactly as its given, though you can use whatever delayed job framework you want. From then on, any counter_cache_on definitions on your models will use that class to make the counter updates.
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 have a question about delayed_job in Rails that doesn't seem to be mentioned much.
When you run a delayed job, it doesn't seem to load anything from ApplicationController. We have some code in ApplicationController to use a custom logger:
def setup_logger
logfile = File.open("#{RAILS_ROOT}/log/audit.log", 'a')
#audit_log = Logger.new(logfile)
$audit_log = #audit_log
end
We then reference $audit_log all through our code. But because DelayedJob doesn't load the ApplicationController this variable is nil and we get errors.
So Delayed_job is just running the specified method blindly, which could also be dangerous
if you rely on before_filters for checking data or validating things.
How can we fix our problem of getting DelayedJob to know about our global logging variable? We don't want to explicitly define the logger all through our code.
How else are people dealing with this problem, as it seems like it should be common, but its not talked about much.
Thanks
Why you think, a Job must run ApplicationController ?
A Job, precisely the worker running that job, loads the environment, sure, but not a controller...
If you don't want have it in a initializer, why not using a kind of config object for storing such data and reference to it in the job ?
And instead of do it in each job individually, I would suggest set up the logger in the BaseJob, and use it in the inherited jobs for what you need.
And another suggestion, please if you can, don't use delayed job, please use http://mperham.github.io/sidekiq/ or at least https://github.com/resque/resque
In my application, I need to execute a task every 5 minutes. The task itself is quite lean, so that's not the problem: the point is that loading the Rails environment uses almost all the CPU of the server. Right now, I'm using whenever with a code like this in my schedule.rb:
every 5.minutes do
runner Task.perform
end
But the cost is too big. Is there anyway to execute this kind of tasks in a preloaded environment? Or any other better solution?
Consider using a background process (many gems, notably delayed job) and implementing a simple "cron" in your code with a polling loop something like
def perform
last = Time.now
while true
if last.sec % (5 * 60) != 0
do_task
last = Time.now
end
end
end
Warning: this example has more holes than a slice of swiss cheese. Write something better :-)
You could use a cron job or set it up to run in a bash script. These would have the advantage of not being tied to your application.
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.