Module: DynamoidLockable

Defined in:
lib/dynamoid_lockable.rb,
lib/dynamoid_lockable/version.rb

Defined Under Namespace

Modules: ClassMethods Classes: CouldNotAcquireLock, CouldNotUnlock, Error, LockingError

Constant Summary collapse

DEFAULT_LOCK_TIME =
15 * 60
VERSION =
"1.0.0"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(other) ⇒ Object



138
139
140
# File 'lib/dynamoid_lockable.rb', line 138

def self.included(other)
  other.extend(ClassMethods)
end

Instance Method Details

#create_relock_thread(name) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/dynamoid_lockable.rb', line 52

def create_relock_thread(name)
  locker_name = self.class.locking_name

  Thread.new do
    config = self.class.lock_config(name)
    loop do
      lock(name, locker_name: locker_name)

      sleep config[:relock_every]
    end
  end
end

#ensure_lockable_field(name) ⇒ Object



81
82
83
# File 'lib/dynamoid_lockable.rb', line 81

def ensure_lockable_field(name)
  self.class.ensure_lockable_field(name)
end

#lock(name, locker_name: self.class.locking_name) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/dynamoid_lockable.rb', line 17

def lock(name, locker_name: self.class.locking_name)
  ensure_lockable_field(name)

  locked_until = Time.now + self.class.lock_config(name)[:duration]

  result = self.class
               .lockable(name, locker_name: locker_name)
               .upsert(
                 hash_key,
                 "#{name}_locked_until": locked_until,
                 "#{name}_locked_by": locker_name
               )

  raise CouldNotAcquireLock unless result

  # Prevents having to call reload, which we've seen take 20seconds
  # but still populates the value in memory, in case the code block
  # calls save and persists this copy again
  send("#{name}_locked_until=", locked_until)
  send("#{name}_locked_by=", locker_name)

  true
end

#perform_with_lock(name) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/dynamoid_lockable.rb', line 65

def perform_with_lock(name)
  ensure_lockable_field(name)
  config = self.class.lock_config(name)

  result = lock(name)

  if config[:relock_every]&.positive?
    relock_thread = create_relock_thread(name)
  end

  yield
ensure
  relock_thread&.exit
  unlock(name) if result # Don't try to unlock if you didn't acquire lock
end

#unlock(name) ⇒ Object

Raises:



41
42
43
44
45
46
47
48
49
50
# File 'lib/dynamoid_lockable.rb', line 41

def unlock(name)
  ensure_lockable_field(name)

  result = self.class.unlockable(name)
               .upsert(hash_key, "#{name}_locked_until": nil)

  raise CouldNotUnlock unless result

  true
end