Skip to content

Instantly share code, notes, and snippets.

@mhenrixon
Last active May 6, 2019 08:03
Show Gist options
  • Save mhenrixon/65b02b64d4035f210d1f8bf8b6178935 to your computer and use it in GitHub Desktop.
Save mhenrixon/65b02b64d4035f210d1f8bf8b6178935 to your computer and use it in GitHub Desktop.
A simple test of async locking with redis blocking methods
require 'bundler/setup'
require 'async/await'
require 'async/redis'
require 'securerandom'
require 'pry'
class AsyncAwaitTest
include Async::Await
attr_reader :digest, :token, :queued_list, :primed_list, :locked_hash
def initialize(key, token)
@digest = key
@token = token
@queued_list = "#{key}:QUEUED"
@primed_list = "#{key}:PRIMED"
@locked_hash = "#{key}:LOCKED"
end
async def blocked_lock
popped_token = redis.brpoplpush(queued_list, primed_list, 0)
redis.hset(locked_hash, token, Time.now.to_f)
popped_token
end
async def queue
redis.lpush(queued_list, token)
end
async def lock(&block)
blocked_lock
queue
barrier!
token
end
async def unlock
redis.hdel(locked_hash, token)
end
async def locked?
redis.hexists(locked_hash, token)
redis.lrem(locked_hash, token)
end
def execute
yield token if block_given?
end
private
def current_time
Process.clock_gettime(Process::CLOCK_MONOTONIC)
end
def redis
@redis ||= Async::Redis::Client.new(endpoint)
end
def endpoint
@endpoint ||= Async::Redis.local_endpoint
end
end
test = AsyncAwaitTest.new(SecureRandom.hex(13), "random")
test.lock.wait
p test.execute do |token|
begin
return yield token if block_given?
token
ensure
test.unlock
end
end
# 1557129781.460516 [0 [::1]:49559] "BRPOPLPUSH" "db1d79c3eb9b7a9da5cc813184:QUEUED" "db1d79c3eb9b7a9da5cc813184:PRIMED" "0"
# 1557129781.460645 [0 [::1]:49560] "LPUSH" "db1d79c3eb9b7a9da5cc813184:QUEUED" "random"
# 1557129781.460999 [0 [::1]:49559] "HSET" "db1d79c3eb9b7a9da5cc813184:LOCKED" "random" "1557129781.4608252"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment