mongoid-locker
Document-level locking for MongoDB via Mongoid. The need arose at Jux from multiple processes on multiple servers trying to act upon the same document and stepping on each other's toes. Mongoid-Locker is an easy way to ensure only one process can perform a certain operation on a document at a time.
Tested against:
- MRI:
2.3.6
,2.4.3
,2.5.0
- Mongoid:
2
,3
,4
,5
,6
,7
See .travis.yml for the latest test matrix.
Usage
Add to your Gemfile
:
gem 'mongoid-locker'
and run bundle install
. In the model you wish to lock, include Mongoid::Locker
after Mongoid::Document
. For example:
class QueueItem
include Mongoid::Document
include Mongoid::Locker
field :locked_at, type: Time
field :locked_until, type: Time
field :completed_at, type: Time
end
Then, execute any code you like in a block like so:
queue_item.with_lock do
# do stuff
queue_item.completed_at = Time.now.utc
queue_item.save!
end
The #with_lock
function takes an optional handful of options around retrying, so make sure to take a look.
The default timeout can also be set on a per-class basis:
class QueueItem
# ...
timeout_lock_after 10
end
Note that these locks are only enforced when using #with_lock
, not at the database level. It's useful for transactional operations, where you can make atomic modification of the document with checks. For example, you could deduct a purchase from a user's balance ... unless they are broke.
More in-depth method documentation can be found at rdoc.info.
Customizable :locked_at and :locked_until field names
By default, Locker uses fields with :locked_at
and :locked_until
names which should be defined in a model.
class User
include Mongoid::Document
include Mongoid::Locker
field :locked_at, type: Time
field :locked_until, type: Time
end
Use Mongoid::Locker.configure
to setup field names which used by Locker for all models where it's included.
Mongoid::Locker.configure do |config|
config.locked_at_field = :global_locked_at
config.locked_until_field = :global_locked_until
end
class User
include Mongoid::Document
include Mongoid::Locker
field :global_locked_at, type: Time
field :global_locked_until, type: Time
end
The locker
method in your model accepts :locked_at_field
and :locked_until_field
options to setup field names which used by Locker for the model. This can be useful when another library uses the same field for different purposes.
class User
include Mongoid::Document
include Mongoid::Locker
field :locker_locked_at, type: Time
field :locker_locked_until, type: Time
locker locked_at_field: :locker_locked_at,
locked_until_field: :locker_locked_until
end
Copyright & License
Copyright (c) 2012-2018 Aidan Feldman & Contributors
MIT License, see LICENSE for more information.