Use Delayed::Job to manage multiple job queues
Since then http://github.com/collectiveidea/delayed_job has reached v3.0 and includes named queues! Excellent for simple grouped queue needs.
Delayed_job - Multiple parallel queues?
With bundler in production:
RAILS_ENV=production bundle exec script/delayed_job -n 4 start
or without bundler
ruby script/delayed_job -n 4 start
Practical use of delayed background job when dealing with many users
Resque is a background processing engine that can support multiple queues.
Ways you could use this:
- Group your tasks into queues that make sense on their priority. If you need fast response times, use it in a 'foreground' queue. Slow? (like sending/receiving emails) can be in the 'background' queue
- Have one queue per user (you will need to have many many workers for this)
This SO question also gives a way to use delayed_jobs with multiple queues/tables
How can I 'consume' jobs from a Delayed Job queue in an app besides the one that 'produces' them
Actually, what you're describing above is correct:
You want to queue an id, and sometimes other required information to identify the record you want to pull from the database, and NOT an object, especially if it's an ActiveRecord::Base
object.
Queuing an object is problematic and can lead to issues. Check my answer at:
https://stackoverflow.com/a/21751030/226255
You can test if your second application is pulling correctly by doing the following in console: (make sure to push a Delayed::Job
to queue first)
Delayed::Job.first.invoke_job
An affordable way to use multiple Delayed::Job queues
Moving to my own server was the way to go. I'm paying under $300/month for a machine that can run 40 workers easily. The downside is having to learn about server administration, but it's not too bad.
Delayed Job One worker for one task (synchronous call)
I can solve this by doing that way
When it assign next same job to another worker, we can add run_at
one second ahead, so multiple workers
does not save object same time and this fix our issue
latest_job = Delayed::Job.where(queue: "order_item_kit").last
run_at = latest_job ? latest_job.run_at + 1.seconds : 1.seconds.from_now
kit_sku.delay(:run_at => run_at,:queue =>"order_item_kit").update_ordere_item
delayed_job: One job per tenant at a time?
Your best bet is probably to spin a custom solution that implements a distributed lock - essentially, the workers all run normally and pull from the usual queues, but before performing work check with another system (Redis, RDBMS, API, whatever) to verify that no other worker is yet performing a job for that tenant. If that tenant is not being worked, then set the lock for the tenant in question and work the job. If the tenant is locked, don't perform the work. It's your call on a lot of the implementation details like whether to move on to try another job, re-enqueue the job at the back of the queue, whether to consider it a failure and bind it to your retry limits, or do something else entirely. This is pretty open-ended, so I'll leave the details to you, but here are some tips:
- Inheritance will be your friend; define this behavior on a base job and inherit from it on the jobs you expect your workers to run. This also allows you to customize the behavior if you have "special" cases for certain jobs that come up without breaking everything else.
- Assuming you're not running through ActiveJob (since it wasn't mentioned), read up on
delayed_job
hooks: https://github.com/collectiveidea/delayed_job/#hooks - they may be an appropriate and/or useful tool - Get familiar with some of the differences and tradeoffs in Pessimistic and Optimistic locking strategies - this answer is a good starting point: Optimistic vs. Pessimistic locking
- Read up on general practices surrounding the concept of distributed locks so you can choose the best tools and strategies for yourself (it doesn't have to be a crazy complicated solution, a simple table in the database that stores the tenant identifier is sufficient, but you'll want to consider the failure cases - how to you manage locks that are abandoned, for example)
Seriously consider not doing this; is it really strictly required for the system to operate properly? If so, it's probably indicative in an underlying flaw in your data model or how you've structured transformations around that data. Strive for ACIDity in your application when thinking about operations on the data and you can avoid a lot of these problems. There's a reason it's not a commonly available "out of the box" feature on background job runners. If there is an underlying flaw, it won't just bite you on this problem but on something else - guaranteed!
How do I separate workers into pools of jobs with delayed job + heroku?
It's in the README for Delayed Job 3:
DJ 3 introduces Resque-style named queues while still retaining DJ-style priority. The goal is to provide a system for grouping tasks to be worked by separate pools of workers, which may be scaled and controlled individually.
Jobs can be assigned to a queue by setting the queue option:
object.delay(:queue => 'tracking').method
Delayed::Job.enqueue job, :queue => 'tracking'
handle_asynchronously :tweet_later, :queue => 'tweets'
script/delayed_job can be used to manage a background process which will start working off jobs.
To do so, add gem "daemons" to your Gemfile and make sure you’ve run rails generate delayed_job
.
You can then do the following:
$ RAILS_ENV=production script/delayed_job start
$ RAILS_ENV=production script/delayed_job stop
# Runs two workers in separate processes.
$ RAILS_ENV=production script/delayed_job -n 2 start
$ RAILS_ENV=production script/delayed_job stop
# Set the --queue or --queues option to work from a particular queue.
$ RAILS_ENV=production script/delayed_job --queue=tracking start
$ RAILS_ENV=production script/delayed_job --queues=mailers,tasks start
Work off queues by setting the QUEUE or QUEUES environment variable.
QUEUE=tracking rake jobs:work
QUEUES=mailers,tasks rake jobs:work
On Heroku, In your procfile, create two entries:
worker1: QUEUE=tracking rake jobs:work
worker2: QUEUES=mailers,tasks rake jobs:work
and scale them individually:
heroku ps:scale worker1=2 worker2=1
etc
concurrency in delayed_jobs
No, one worker cannot run two jobs concurrently, you need more than one process running for that.
In the example you are describing, you are starting a worker that is running in the foreground (rake job:work
), but what you could do instead, is to start them as background workers, by running bin/delayed_job
instead (script/delayed_job
for earlier versions). That command has multiple options that you can use to specify how you want delayed_job to function.
One of the options is -n
or --number_of_workers=workers
. That means you can start two workers by running the following command:
bundle exec bin/delayed_job --number_of_workers=2 start
It is also possible to dedicate certain workers to only run jobs from a specific queue, or only high priority jobs.
Related Topics
How to Modify a Text File in Ruby
Parsing Date from Text Using Ruby
Rails: Model Instance Method or Helper Method
Your Ruby Version Is 2.2.4, But Your Gemfile Specified 2.3.0
Ruby: Uri::Invalidurierror (Uri Must Be Ascii Only
Understanding Ruby Splat in Ranges and Arrays
How to Shorten a Uuid to a Specific Length
How to Use Variables in a Yaml File
How to Round a Float to a Specified Number of Significant Digits in Ruby
How to Know the Current Rake Task
Ruby Can Not Access Variable Outside the Method
Ruby 1.9 Doesn't Support Unicode Normalization Yet
Rake Aborted! Stack Level Too Deep
Ruby - Extracting the Unique Values Per Key from an Array of Hashes
Ruby Google_Drive Gem Oauth2 Saving