Module: Mongoid::Locker
- Defined in:
- lib/mongoid/locker.rb,
lib/mongoid/locker/errors.rb,
lib/mongoid/locker/version.rb,
lib/mongoid/locker/wrapper.rb
Defined Under Namespace
Modules: ClassMethods, Errors, Wrapper
Constant Summary collapse
- MODULE_METHODS =
Available parameters for
Mongoid::Locker
module, a class where the module is included and it’s instances. %i[ locking_name_field locked_at_field maximum_backoff lock_timeout locker_write_concern backoff_algorithm locking_name_generator ].freeze
- VERSION =
'2.2.0'
Class Method Summary collapse
-
.configure {|_self| ... } ⇒ Object
Sets configuration using a block.
-
.exponential_backoff(_doc, opts) ⇒ Float
Returns random number of seconds depend on passed options.
- .included(klass) ⇒ Object private
-
.locked_at_backoff(doc, opts) ⇒ Float | Integer, 0
Returns time in seconds remaining to complete the lock of the provided document.
-
.reset! ⇒ Object
Resets to default configuration.
-
.secure_locking_name(_doc, opts) ⇒ String
Generates secure random string of name#attempt format.
Instance Method Summary collapse
-
#has_lock? ⇒ Boolean
Returns whether the current instance has the lock or not.
-
#locked? ⇒ Boolean
Returns whether the document is currently locked in the database or not.
-
#with_lock(**opts) ⇒ Object
Executes the provided code once the document has been successfully locked.
Class Method Details
.configure {|_self| ... } ⇒ Object
Sets configuration using a block.
85 86 87 |
# File 'lib/mongoid/locker.rb', line 85 def configure yield(self) if block_given? end |
.exponential_backoff(_doc, opts) ⇒ Float
Returns random number of seconds depend on passed options.
47 48 49 |
# File 'lib/mongoid/locker.rb', line 47 def exponential_backoff(_doc, opts) 2**opts[:attempt] + rand end |
.included(klass) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/mongoid/locker.rb', line 105 def included(klass) klass.extend ClassMethods klass.singleton_class.instance_eval { attr_accessor(*MODULE_METHODS) } klass.locking_name_field = locking_name_field klass.locked_at_field = locked_at_field klass.lock_timeout = lock_timeout klass.locker_write_concern = locker_write_concern klass.maximum_backoff = maximum_backoff klass.backoff_algorithm = backoff_algorithm klass.locking_name_generator = locking_name_generator klass.delegate(*MODULE_METHODS, to: :class) klass.singleton_class.delegate(*(methods(false) - MODULE_METHODS.flat_map { |method| [method, "#{method}=".to_sym] } - %i[included reset! configure]), to: self) end |
.locked_at_backoff(doc, opts) ⇒ Float | Integer, 0
Returns time in seconds remaining to complete the lock of the provided document. Makes requests to the database.
61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/mongoid/locker.rb', line 61 def locked_at_backoff(doc, opts) return doc.maximum_backoff if opts[:attempt] * doc.lock_timeout >= doc.maximum_backoff locked_at = Wrapper.locked_at(doc).to_f return 0 unless locked_at > 0 current_time = Wrapper.current_mongodb_time(doc.class).to_f delay = doc.lock_timeout - (current_time - locked_at) delay < 0 ? 0 : delay + rand end |
.reset! ⇒ Object
Resets to default configuration.
93 94 95 96 97 98 99 100 101 102 |
# File 'lib/mongoid/locker.rb', line 93 def reset! # The parameters used by default. self.locking_name_field = :locking_name self.locked_at_field = :locked_at self.lock_timeout = 5 self.locker_write_concern = { w: 1 } self.maximum_backoff = 60.0 self.backoff_algorithm = :exponential_backoff self.locking_name_generator = :secure_locking_name end |
.secure_locking_name(_doc, opts) ⇒ String
Generates secure random string of name#attempt format.
30 31 32 |
# File 'lib/mongoid/locker.rb', line 30 def secure_locking_name(_doc, opts) "#{SecureRandom.urlsafe_base64}##{opts[:attempt]}" end |
Instance Method Details
#has_lock? ⇒ Boolean
Returns whether the current instance has the lock or not.
231 232 233 |
# File 'lib/mongoid/locker.rb', line 231 def has_lock? @has_lock || false end |
#locked? ⇒ Boolean
Returns whether the document is currently locked in the database or not.
220 221 222 |
# File 'lib/mongoid/locker.rb', line 220 def locked? persisted? && self.class.where(_id: id).locked.limit(1).count == 1 end |
#with_lock(**opts) ⇒ Object
Executes the provided code once the document has been successfully locked. Otherwise, raises error after the number of retries to lock the document is exhausted or it is reached ClassMethods#maximum_backoff limit (depending what comes first).
248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/mongoid/locker.rb', line 248 def with_lock(**opts) opts = opts.dup opts[:retries] ||= Float::INFINITY opts[:reload] = opts[:reload] != false acquire_lock(opts) if persisted? && (had_lock = !has_lock?) begin yield ensure unlock!(opts) if had_lock end end |