Skip to content

Instantly share code, notes, and snippets.

@mloughran
Created November 21, 2011 13:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mloughran/1382605 to your computer and use it in GitHub Desktop.
Save mloughran/1382605 to your computer and use it in GitHub Desktop.
Potential async transaction api for em-hiredis
require 'em-hiredis'
class EM::Hiredis::Client
class Transaction
include EM::Deferrable
def initialize(redis)
@redis = redis
end
def prep(&block)
@prep = block
end
def multiexec(&block)
# Raise if called more than once
@multiexec = block
end
def run(retries = 3)
df = EM::DefaultDeferrable.new
@prep.call(@redis, df)
df.callback { |prep_results|
@redis.multi
@multiexec.call(@redis, *prep_results)
df2 = @redis.exec { |results|
if results.nil?
if retries > 0
EM.next_tick { run(retries - 1) }
else
# Transaction failed
# TODO: Clear the watches
self.fail()
end
else
self.succeed(*results)
end
}
}
df.errback {
# Decided not to excecute the multi-exec
# TODO: Clear the watches
}
end
end
def atomically(retries = 3)
transaction = Transaction.new(self)
yield transaction
transaction.run(retries)
return transaction
end
end
EM.run {
redis = EM::Hiredis.connect
df = redis.atomically do |transaction|
transaction.prep { |r, df|
r.watch('foo')
EM.add_timer(3) {
r.get('foo') { |value|
df.succeed(value)
}
}
}
transaction.multiexec { |r, foo|
p "setting bar to #{foo}"
r.set('foo', rand)
r.set('bar', foo)
}
end
df.callback { |set1, set2|
p [:transaction_result, set1, set2]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment