#171 Delayed Job
Jul 20, 2009 | 10 minutes | Plugins, Background Jobs
Is there a long running task which should be handled in the background? One of the best ways is using the delayed_job plugin like I show in this episode.
- Download:
- source code
- mp4
- m4v
- webm
- ogv
Awesometastic as always! :) Thx Ryan for your hard work!
Ryan,
Can you comment on why is DelayedJob better than BackgroundRb or Workling?
Here is a great resource on handling bg file upload on Amazon S3 with starling/workling: http://aaronvb.com/blog/2009/7/19/paperclip-amazon-s3-background-upload-using-starling-and-workling
I've been using workling, backgroundDRb, but delayed_job is much better, it just works without any problems
thanks
@Vlad, delayed_job is simpler than both Workling and BackgroundRb. It can also scale really well (it's used on GitHub). And overall it feels more stable.
THANK YOU!!! I needed this right now! I have been having so many problems with workling lately and it seems as though the developers have abandon support. I was working on a fix at this very moment and here it is! I love that this is the queue and worker all rolled into one!
The one piece of information I was looking for: how are the workers informed about jobs - actively by asking (polling), or passively by being called? Turns out it's polling - the SAME as all the other options I've seen.
That makes it just as bad as all those other options. On a 2009(!) computer system it should be possible to implement something like that WITHOUT wasting CPU cycles on polling.
Why can't the piece of code that pushes the new job information into the database (delayed job) or into memcache (workling/starling) also directly wake a thus far sleeping worker? Why does everyone only write code that actively asks "is there new work for me?" "is there new work for me?" "is there new work for me?" as often as several times per second (here, delayed job, uses 5s by default I just read)?
Okay, on a modern CPU one might argue that it really does not matter. However, what troubles me is that the same kind of "oh it does not matter in the grand scheme of things" is applied a little too often - which is why today we need so much CPU power in the first place to run a library using a library using a library using a library running in a virtual system in a virtual machine in a virtual machine (this term does not only apply to vmware/xen/etc.) fully simulated PCs).
Yes, I'm ranting. I've just been informed about the n+1-th "even greater" background job processing plugin for rails - which STILL uses polling.
Nice!
If anyone has additional info on one of the following, please post it!
1. saving how far the job made it so that it can resume from a failure without duplicating work (particularly useful for newsletters as Ryan mentioned)
2. running the delayed_job worker process from a different server
Thanks!
Brian
Ryan,
I have been watching this screencast series for along time now, but you still keep nailing episodes. This is no exception.
Thanks for the Structs, never seen that before.
It's really useful. Thank you!
But I'll guess, I'm gonna create a app/jobs directory instead using the lib dir.
Is it possible to create reoccurring jobs like for every hour?
Ryan, great episode. I've been using Spawn:
http://github.com/tra/spawn/tree/master
It's quite a bit easier to set up and use compared to delayed_job - no migration and no rake task necessary. I was wondering, what do you see as the main advantages of delayed_job over Spawn?
You can also use the following to invoke Rake tasks from Delayed Job.
http://geminstallthat.wordpress.com/2008/02/25/run-rake-tasks-with-delayedjob-dj/
Hi Ryan/All,
I've been working on some background tasks lately and was hoping delayed_job would be a solution, but it doesn't seem like it will be.
1) Does delayed_job handle job dependencies? Sometimes you need to spawn 2 jobs, where job 2 depends on job 1 being completed
2) How does delayed_job deal with concurrency, specifically in the development environment using SQLite3? We've found issues using SQLite3 with our current background job framework. So I'm wondering what will happen if you have some background jobs that actively query/update active record classes? I would expect SQLite::BusyExceptions to occur in heavy traffic/many job scenarios.
3) I also share the question from Brian about the ability to run jobs on a remote server. Our current solution is to have the job itself invoke the commands on the remote server, and then collect the results via POpen4.
Thanks for any additional info. I would love to use a community supported gem to handle my background jobs, but our home baked solution is the only thing that has worked so far.
I have been using Workling+Sparkling for a while in production and I have just tested DelayedJob. D.J is really easier to use and run. I would recommend that.
Hello Ryan,
I've tried starting up the job processes in production with the command:
script/delayed_job -e production -n 1 start
but I get this error:
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require': no such file to load -- daemons (LoadError)
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
from ./script/../vendor/plugins/delayed_job/lib/delayed/command.rb:2
from script/delayed_job:6:in `require'
from script/delayed_job:6
any ideas on how to fix it?
Thanks a lot.
Ivan
@Michael H.
I think the reason it doesn't work that way is that they are trying to separate the different processes. Waking a process would require the different processes to know about each other, and this way they all work independently of each other. The amount of cpu time consumed by each process to poll when there is no work is really insignificant. The resources consumed when they are actually doing something is far more important, and that wouldn't be improved by a 'wake on demand' system. Also, the more direct interaction you have between the different processes, the greater the fragility of the whole system.
There are a few good reasons all of these systems all use this polling method. Your question is a good one, but there are reasons they are done this way in general. For certain specific cases, a 'wake on demand' system will make more sense, but in general, a polling system is going to be better.
Is there no built in way to let the user know when a job has finished processing?
Great tutorial Cheers
Ryan T
Can anyone provide an example of using delayed_job with ActionMailer (deliver method with params)?
@James R. I think that would just be send_later(:deliver, your_params_here). That would be the same as Object.deliver(your_params_here). Is that what you were asking?
Hi guys, nice screen but I prefer job_fu more clean and easier
http://github.com/jnstq/job_fu/tree/master
cheers!
Ryan;
Thanks for covering Delayed Job.
I spent a few evenings trying to get workling/starling up (based on an earlier Railscast) and running but ultimately passed on completing the work.
Delayed Job fit in nicely to my existing, was easy to deploy. Taken care of in a couple of hours.
@Ivan: You need to install the daemon gem:
sudo gem install daemons
Awesome work again Ryan!
Ryan, could you make a cast that combines delayed_job with multiple ajax actions (redirects or updates)?
See my problem is the following: In the index action of the controller I show all entries of a database. Background jobs are started within the index action. Now on every entry listed I have a .gif that shows loading. After a job is finished this .gif image should be replaced by an arrow image for success or by a X image for failed.
Now obviosly I would have to call ajax for every lib job, but umfortunately I wasn't able to achive this until now cause its tricky or probably not possible to call an action or a rjs file from outside the controller itself that would replace the corresponding div id.
Would be nice to see how you would solve that!
Does anyone know how to get the "worker" started automatically instead of having to type "rake jobs:work" in a console? Ie. make it start when the server starts or something.
Nice tutorial btw, it was exactly what I was looking for! :-)
I just created a plug in that uses delayed_job to send emails asynchronously by default.
Check it out at http://github.com/andersondias/delayed_job_mailer
Thanks Ryan. Great cast as always.
This looks like a very useful bit of kit for queue processing.
I think it might have paid to mention how often queue processing logic gets complicated (no mater how stable of scalable the technical implication of the queue processor is). It just does in the real world.
I think it would have been good to talk at least a little about the best way to execute the queue processor script itself.
While the daemon approach will probably give you slicker results, there is quite a bit of hidden overhead with daemons on production systems.
- they HAVE to be running. There has to be a monitoring test to make sure they're running.
- they must gracefully start and stop with the system. We have to be sure that this is going to work.
- nice if they handle non-graceful shutdown of server (i.e. power failure). Often there is a lockfile/pidfile somewhere that may prevent this.
We all do a lot of web development where this side of a server's BAU behaviour is hidden behind tried and tested daemon applications (Apache, MySQL, MTAs) that take care of all of this for us.
Although a little more primative, a cron job might be a better option for those who are not ready to be writing init scripts on a production server.
Thanks
Great 'Cast as always. It looks like your source code is pointing to episode 170 rather than 171.
I used delayed_job to process resizing in the background on Heroku:
http://blog.madeofcode.com/post/201282903/paperclip-s3-delayed-job-in-rails
Hello Ryan,
I saw that you have now several episodes on background-processing options: system call+rake, whenever/cron + rake/runner, starling+workling and now delayed_job. Would you have one on BackgroundJob and how it fares against all these options you surveyed? It will be a great summary comparison reference. Besides, even though delayed_job is getting popular (e.g. github and what not), it seems that BackgroundJob is also heartily recommended (e.g. EngineYard) among the serious, production-ready contenders. It would be great to see what your take is on this. Thanks.
Hi
How can I determine if a job is finished ? Ideally there would be a way for my rails app to - upon request, determine if a specific job is complete. It seems to me that in order to do that you would need to get some unique id upon creating a delayed job, return that to the user - who could then pass that id to the app and ask 'is "this" (aka insert delayed job id here) job done yet ?"
Is this possible and if so - how ?
Thanks
I noticed that I was getting the error nil.now when starting the rake jobs:work so I had to apply the patch from this link
http://github.com/kossnocorp/delayed_job/blob/master/lib/delayed/job.rb#L251
Anyone experiencing issues with model.update_attributes command inside delayed jobs? I can't seem to get them working.
Hey Ryan,
I'm using a hosting company (Dreamhost) that doesn't allow me running daemons in the background all the time. Eventually the just stop the processes. What would my options be to run actionmailer in the background without a daemon running?
thanks so much!
Hi, Ryan
I want to ask what problems may occur if when i need to do some long lasting job i create new Thread and let it handle all the work and i continue with my request. So basically:
action start
Thread.new{long action}
action end
Hello, thanks for the cast :)
Unfortunately i get the following error:
can't dump anonymous class Class
i have the following code:
def datei_speichern(pfad)
name = File.basename(pfad)
teile = pfad.split("?")
puts teile.size
puts pfad
if teile.size == 2
puts "PHP-Skript"
else
if db_vergleich_neu(name)
datei = @agent.get(pfad)
datei.save_as('l://trebble//teufel//' + @titel + "/" + name)
end
end
rescue
puts "fehler"
end
handle_asynchronously :datei_speichern
Any Idea whats wrong?
einar, I have such error to:
can't dump anonymous class Class (TypeError)
I fix it. See http://d.hatena.ne.jp/milk1000cc/20091002/1254442030
Seems need remove any code under initialize to perform function in job
Error code:
class CrawlJob
def initialize
@agent = WWW::Mechanize.new
end
def perform
...
end
end
True code:
class CrawlJob
def perform
@agent = WWW::Mechanize.new
...
end
end
Oh... It is not work on lib folder. On controller it is work ok
FYI: send_later will not work when calling it on an ActionMailer class, when using the collectiveidea version of delayed_job. If you want to call something like UserMailer.send_later ... you can use Tobi's original version of the gem: http://github.com/tobi/delayed_job
This likely changed since last year when Ryan did this screencast.
PS: Thanks Ryan for the awesome work you do!
I'm just wondering.. how would it look like when you want to notify the user if the task was done successful or not? I miss a link between the jobs table and my table. Clearly, i could do something like that myself but I'm wondering if someone has an elegant solution.
Hi
How can I determine if a job is finished ?
The delayed_job plugin is amazing, I use it in several apps. The biggest problem with it is the lack of monitoring of the daemonized process and the jobs themselves.
To address these issues I wrote the delayed_job_tracer plugin, which will monitor your delayed job process and send you an e-mail if delayed_job crashes or if one of its jobs fail.
Here's an article that describes how it works:
http://modernagility.com/articles/5-monitoring-delayed_job-and-its-jobs
Ryan, it might be interesing to modify your example
mailing.send_later(:deliver)
is deprecated. It looks like you now have to use
mailing.delay.deliver
Also for those who asked how to know when the job is finished one solution is to "do something" (in my case, call *again* the delay to restart again) at the end of the delayed method.
Good job,nice blog.I think i'ts very wonderful
It took me 3 hours, but I finally got delayed job working with paperclip. If anyone is interested, here are couple blog posts I used:
http://ezror.com/blog/index.shtml
http://madeofcode.com/posts/42-paperclip-s3-delayed-job-in-rails
From the collectiveidea docs, I'm seeing this:
"By default all jobs are scheduled with priority = 0, which is top priority. You can change this by setting Delayed::Worker.default_priority to something else. Lower numbers have higher priority."
This seems to contradict what was stated about priority in the screencast. If lower numbers have higher priority, then shouldn't negative numbers trump 0?
can anyone tell me what if delayed_job stop and start working next day then how I will figure out the missing date mails or documents ...etc..
This is really useful and went 99% of the way to getting me going with CollectiveIdea's Delayed::Job plugin with Rails3. However, one absolutely crucial but missing piece from this Railscast, at least with respect to Rails3 is that without adding a line to your config/application.rb file to load your lib/mailing_job.rb file when your application is initialize!d means that your class definition will not be available to the jobs:work rake task when it tries to dequeue a job from the database and run it. As such, you will see jobs queuing and dequeuing, but nothing will happen; your perform method will not be called because your class will not be available to Delayed::Job when it YAML::load()s your delayed job.
Thank you .. Although a couple of years old, this is an excellent railscast !
What should i do if i want to set max_attempts for one job to 3 and some other job to 20 ? I just started using delayed_job, so i know of only place to put such configurations (initializers delayed_job_config). But is it possible to have separate configurations per job ? for example , separate config file for mailers_job and news_letters job.
More about Struct: Random Ruby Tricks: Struct.new by Steve Klabnik.
It is possible to have more than one delayed job process doing the same task on the same server?
Hello,
I had some trouble getting custom jobs to work.
Requiring the job.rb file was not enough, I had to configure autoload paths.
Placing my jobs in #{root}/jobs and setting this in application.rb did the trick!
Hi all,
I have the same problem as http://stackoverflow.com/questions/15618099/multiple-delayed-job-processes-starting-same-job
I'm using: collectiveideas delayed_job 1.8.2, ruby ee 1.8.7 2012.02, pgbouncer + postgresql 9.2.
Regards