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.1.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.
86 87 88 |
# File 'lib/mongoid/locker.rb', line 86 def configure yield(self) if block_given? end |
.exponential_backoff(_doc, opts) ⇒ Float
Returns random number of seconds depend on passed options.
48 49 50 |
# File 'lib/mongoid/locker.rb', line 48 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.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/mongoid/locker.rb', line 106 def included(klass) klass.extend(Forwardable) unless klass.ancestors.include?(Forwardable) 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.def_delegators(klass, *MODULE_METHODS) 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.
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/mongoid/locker.rb', line 62 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.
94 95 96 97 98 99 100 101 102 103 |
# File 'lib/mongoid/locker.rb', line 94 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.
31 32 33 |
# File 'lib/mongoid/locker.rb', line 31 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.
234 235 236 |
# File 'lib/mongoid/locker.rb', line 234 def has_lock? @has_lock || false end |
#locked? ⇒ Boolean
Returns whether the document is currently locked in the database or not.
223 224 225 |
# File 'lib/mongoid/locker.rb', line 223 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).
251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/mongoid/locker.rb', line 251 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 |