Postqueue
The postqueue gem implements a simple to use queue on top of postgresql. Since this implementation is using the SKIP LOCKED syntax, it needs PostgresQL >= 9.5.
Why not using another queue implementation? postqueue comes with some extras:
- support for optimal handling of idempotent operations
- batch processing
- searchable via SQL
Basic usage
queue = PostgresQL::Base.new
queue.enqueue op: "myop", entity_type: "mytype", entity_id: 12
queue.process do |op, entity_type, entity_ids|
# note: entity_ids is always an Array of ids.
case "#{op}/#{entity_type}"
when "reindex/product"
Product.index_many(Product.where(id: entity_ids))
else
raise "Unsupported op/entity_type: #{op}/#{entity_type}"
end
end
The callback will receive the op and entity_type attributes and the entity_ids of all queue entries
selected for processing. If the block fails, by either returning false or by raising an exception the
queue entries are postponed a bit, up until Postqueue::MAX_ATTEMPTS times (which currently is defined as 5).
The method will return the return value of the block.
If no callback is given the return value will be the [op, entity_type, entity_ids] values that would have
been sent to the block. This is highly unrecommended though, since when using a block to do processing errors
and exceptions can properly be dealt with.
Postqueue.process also accepts the following arguments:
entity_type: only process entries with thisentity_type;op: only process entries with thisopvalue;batch_size: when the first matching entry supports batch processing limit the size of the batch to the bassed in size.
Example:
Postqueue.process(entity_type: 'Product', batch_size: 10) do |op, entity_type, entity_ids|
# only handle Product entries
end
If the queue is empty or no matching queue entry could be found, both Postqueue.process and Postqueue.process_one will return nil.
process a single entry
For the simple just-give-me-the-next use case there is a shortcut, which only processed the first matching entry. Under the hood this calls Postqueue.process with batch_size set to 1.
Postqueue.process_one do |op, entity_type, entity_ids|
end
Note that even though process_one will only ever process a single entry the entity_ids parameter to the block is still an array (holding a single ID in that case).
idempotent operations
If queue items represent idempotent operations they need not be run repeatedly, but only once. To implement idempotent
operations, subclass Postqueue::Base and reimplement the idempotent? method. The following marks all "reindex"
ops as idempotent:
class Testqueue < Postqueue::Base
def idempotent?(entity_type:,op:)
op == "reindex"
end
end
batch processing
Often queue items can be processed in batches for a better performance of the entire system. To enable
batch processing for some items subclass Postqueue::Base and reimplement the batch_size? method
to return a suggested batch_size for a specific operation. The following implements a batch_size of 100
for all queue entries:
class Testqueue < Postqueue::Base
def batch_size(entity_type:,op:)
100
end
end
Searchable via SQL
In contrast to other queue implementations available for Rubyists this queue formats entries in a way that makes it possible to query the queue via SQL. On the other hand this queue also does not allow to enqueue arbitrary entries as these others do.
Installation
Add this line to your application's Gemfile:
gem 'postqueue'
And then execute:
$ bundle
Or install it yourself as:
$ gem install postqueue
Usage
Development
After checking out the repo, run bin/setup to install dependencies. Make sure you have a local postgresql implementation of
at least version 9.5. Add a postqueue user with a postqueue password, and create a postqueue_test database for it.
The script ./scripts/prepare_pg can be helpful in establishing that.
Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install.
To release a new version, run ./scripts/release, which will bump the version number, create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/postqueue.
License
The gem is available as open source under the terms of the MIT License.