Skip to content

Instantly share code, notes, and snippets.

@stefanvermaas
Forked from ikzekly/temporary_lock.rb
Last active August 4, 2022 17:36
Show Gist options
  • Save stefanvermaas/0ad93219968576e932617fdf5b3b6839 to your computer and use it in GitHub Desktop.
Save stefanvermaas/0ad93219968576e932617fdf5b3b6839 to your computer and use it in GitHub Desktop.
Provides Redis distributed lock api
# frozen_string_literal: true
# @example provides Redis distributed lock api
#
# $ TemporaryLock.create!(:example, 'c22a0420-51c8-4e47-843c-92a37e8d2eba')
# => #<TemporaryLock:0x000055b43e328410 @key="temporary_lock:example:c22a0420-51c8-4e47-843c-92a37e8d2eba">
#
# @example raises `TemporaryLock::StaleObjectError` when `id` already registered
#
# $ TemporaryLock.create!(:example, 'c22a0420-51c8-4e47-843c-92a37e8d2eba')
# => TemporaryLock::StaleObjectError: Attempted to update a stale object: temporary_lock:example:c22a0420-51c8-4e47-843c-92a37e8d2eba
# => from /app/app/models/temporary_lock.rb:21:in `create!'
class TemporaryLock
class EmptyIdError < StandardError; end
class StaleObjectError < StandardError; end
EXPIRE = 14.days.to_i
attr_reader :key
def self.create!(name, id)
temporary_lock = new(name, id)
return temporary_lock if temporary_lock.lock!
raise StaleObjectError.new(
"Attempted to update a stale object: #{temporary_lock.key}"
)
end
def initialize(name, id)
@key = redis_key!(name, id)
end
def lock!
redis_client.set(
key,
serialize(true),
ex: EXPIRE,
nx: true
)
end
private
def serialize(data)
Oj.dump(data)
end
def redis_key!(name, id)
raise EmptyIdError.new('Tried lock with empty `id`') unless id.presence
[:temporary_lock, name, id].join(':')
end
def redis_client
Redis::Namespace.new(
'mejuri-redis-lock',
redis: Redis.new(
host: ENV['REDIS_HOST'],
port: ENV['REDIS_PORT'],
db: ENV['REDIS_DB'].to_i
)
)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment