A lock that does not timeout can lead to a standstill and manual cleanup. Simple solution: redis ‘set ex nx’ and memcached ‘add’.
When indefinite locks happen, getting information on why they happen helps to debug the locking mechanism and see if the processes always fail to unlock.
A softer locking approach to receive feedback when locks expire:
Code
def lock
timeout = 30
key = 'lock'
now = Time.now.to_i
if redis.setnx(key, "#{now}-#{Process.pid}-#{Socket.gethostname}")
yield
elsif (old = redis.get(key)) && now > old.to_i + timeout
logger.error("Releasing expired lock #{old}")
redis.delete(key) # next process can get the lock
end
end
Not 100% safe since the delete could cause multiple processes to get a lock, but depending on your usecase this might be an ok tradeoff.