Redis lock implementation The 2019 Stack Overflow Developer Survey Results Are InRead-write lock implementation for Ruby, new versionChat logger using RedisSpin-lock implementationRedis Message Queue (Cloud)Token generating library on RedisSilly redis implementationRedis protocol implementation by KotlinRedis lookup with a default valueRedis lua - game leaderboard “overview”Reader Writer Lock Implementation

Is it ok to offer lower paid work as a trial period before negotiating for a full-time job?

Button changing its text & action. Good or terrible?

Does adding complexity mean a more secure cipher?

Old scifi movie from the 50s or 60s with men in solid red uniforms who interrogate a spy from the past

How come people say “Would of”?

Accepted by European university, rejected by all American ones I applied to? Possible reasons?

Are spiders unable to hurt humans, especially very small spiders?

Is an up-to-date browser secure on an out-of-date OS?

Can I have a signal generator on while it's not connected?

Getting crown tickets for Statue of Liberty

Is it possible for absolutely everyone to attain enlightenment?

What to do when moving next to a bird sanctuary with a loosely-domesticated cat?

Why couldn't they take pictures of a closer black hole?

How much of the clove should I use when using big garlic heads?

If a sorcerer casts the Banishment spell on a PC while in Avernus, does the PC return to their home plane?

How to obtain a position of last non-zero element

Can you cast a spell on someone in the Ethereal Plane, if you are on the Material Plane and have the True Seeing spell active?

What is the meaning of Triage in Cybersec world?

Why didn't the Event Horizon Telescope team mention Sagittarius A*?

Geography at the pixel level

Why not take a picture of a closer black hole?

What is preventing me from simply constructing a hash that's lower than the current target?

What do hard-Brexiteers want with respect to the Irish border?

For what reasons would an animal species NOT cross a *horizontal* land bridge?



Redis lock implementation



The 2019 Stack Overflow Developer Survey Results Are InRead-write lock implementation for Ruby, new versionChat logger using RedisSpin-lock implementationRedis Message Queue (Cloud)Token generating library on RedisSilly redis implementationRedis protocol implementation by KotlinRedis lookup with a default valueRedis lua - game leaderboard “overview”Reader Writer Lock Implementation



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








1












$begingroup$


Considering I'm not implementing distributed lock mechanism, is this code correct and clear?



class RedisLock
class NotAcquired < StandardError; end

def initialize(redis)
@redis = redis
end

def lock(key, expiration_ms)
val = SecureRandom.random_number(100000000000000000).to_s

if @redis.set(key, val, nx: true, px: expiration_ms)
yield
unlock(key, val)
true
else
false
end
end

def lock!(*args, &block)
unless lock(*args, &block)
raise NotAcquired.new("Could not acquire lock with #args")
end
end

def unlock(key, val)
check_and_delete = <<-LUA
if redis.call('get', KEYS[1]) == KEYS[2] then
redis.call('del', KEYS[1])
end
LUA

@redis.eval(check_and_delete, [key, val])
end
end


RedisLock.new(Redis.current).lock!('key', 10000) do_something









share|improve this question











$endgroup$




bumped to the homepage by Community 31 mins ago


This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.





















    1












    $begingroup$


    Considering I'm not implementing distributed lock mechanism, is this code correct and clear?



    class RedisLock
    class NotAcquired < StandardError; end

    def initialize(redis)
    @redis = redis
    end

    def lock(key, expiration_ms)
    val = SecureRandom.random_number(100000000000000000).to_s

    if @redis.set(key, val, nx: true, px: expiration_ms)
    yield
    unlock(key, val)
    true
    else
    false
    end
    end

    def lock!(*args, &block)
    unless lock(*args, &block)
    raise NotAcquired.new("Could not acquire lock with #args")
    end
    end

    def unlock(key, val)
    check_and_delete = <<-LUA
    if redis.call('get', KEYS[1]) == KEYS[2] then
    redis.call('del', KEYS[1])
    end
    LUA

    @redis.eval(check_and_delete, [key, val])
    end
    end


    RedisLock.new(Redis.current).lock!('key', 10000) do_something









    share|improve this question











    $endgroup$




    bumped to the homepage by Community 31 mins ago


    This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.

















      1












      1








      1





      $begingroup$


      Considering I'm not implementing distributed lock mechanism, is this code correct and clear?



      class RedisLock
      class NotAcquired < StandardError; end

      def initialize(redis)
      @redis = redis
      end

      def lock(key, expiration_ms)
      val = SecureRandom.random_number(100000000000000000).to_s

      if @redis.set(key, val, nx: true, px: expiration_ms)
      yield
      unlock(key, val)
      true
      else
      false
      end
      end

      def lock!(*args, &block)
      unless lock(*args, &block)
      raise NotAcquired.new("Could not acquire lock with #args")
      end
      end

      def unlock(key, val)
      check_and_delete = <<-LUA
      if redis.call('get', KEYS[1]) == KEYS[2] then
      redis.call('del', KEYS[1])
      end
      LUA

      @redis.eval(check_and_delete, [key, val])
      end
      end


      RedisLock.new(Redis.current).lock!('key', 10000) do_something









      share|improve this question











      $endgroup$




      Considering I'm not implementing distributed lock mechanism, is this code correct and clear?



      class RedisLock
      class NotAcquired < StandardError; end

      def initialize(redis)
      @redis = redis
      end

      def lock(key, expiration_ms)
      val = SecureRandom.random_number(100000000000000000).to_s

      if @redis.set(key, val, nx: true, px: expiration_ms)
      yield
      unlock(key, val)
      true
      else
      false
      end
      end

      def lock!(*args, &block)
      unless lock(*args, &block)
      raise NotAcquired.new("Could not acquire lock with #args")
      end
      end

      def unlock(key, val)
      check_and_delete = <<-LUA
      if redis.call('get', KEYS[1]) == KEYS[2] then
      redis.call('del', KEYS[1])
      end
      LUA

      @redis.eval(check_and_delete, [key, val])
      end
      end


      RedisLock.new(Redis.current).lock!('key', 10000) do_something






      ruby locking redis






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Mar 22 '17 at 12:42









      200_success

      131k17157422




      131k17157422










      asked Feb 9 '17 at 18:26









      cutalioncutalion

      1645




      1645





      bumped to the homepage by Community 31 mins ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.







      bumped to the homepage by Community 31 mins ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.






















          1 Answer
          1






          active

          oldest

          votes


















          0












          $begingroup$

          Here's a stab at clarifying the intent without changing any of the functionality. I didn't try to run it or anything, so don't hold me to syntax.



          # handles locking and unlocking redis for a particular operation
          class RedisLock
          # thrown when a lock cannot be acquired
          class NotAcquired < StandardError; end

          # since the redis key and ms are used in pretty much every method,
          # might as well go ahead and pass them in the constructor.
          # set defaults here if there are defaults that make sense.
          # make a yardoc comment and describe what these all are.
          def initialize(redis: Redis.current, nx: true, redis_key:, expiration_ms:)
          @redis = redis
          @redis_key = redis_key
          @expiration_ms = expiration_ms
          @nx = nx
          end

          # call it with_lock instead of lock
          # to make it more apparent it accepts a block
          def with_lock!
          raise(NotAcquired, "Could not acquire lock with #args") unless lock
          yield
          unlock(redis_key, random_lock_number)
          true # do you really need to return true here?
          end

          def with_lock
          with_lock!
          rescue NotAcquired
          false
          end

          private

          # set instance variables in the initializer, but never call them directly.
          attr_reader :redis, :redis_key, :expiration_ms, :nx

          def lock
          redis.set(redis_key, random_lock_number, nx: nx, px: expiration_ms)
          end

          # number is a little decieving here when you call `.to_s` at the end.
          # can you use SecureRandom.uuid instead?
          def random_lock_number
          @random_lock_number ||= SecureRandom.random_number(100_000_000_000_000_000).to_s
          end

          # no need for this to be exposed publicly.
          # calling eval directly is usually a bad idea.
          def unlock
          redis.eval(redis_check_and_delete, [redis_key, random_lock_number])
          end

          def redis_check_and_delete
          <<-LUA
          if redis.call('get', KEYS[1]) == KEYS[2] then
          redis.call('del', KEYS[1])
          end
          LUA
          end
          end


          And to call it:



          RedisLock.new(redis_key: 'key', expiration_ms: 10000).with_lock! do_something 





          share|improve this answer











          $endgroup$












          • $begingroup$
            Hi @Chris! Thanks you for the answer! Though I cannot agree with the suggested improvements. The general concern about it is that the new object cannot be re-used with another key. Moreover it even cannot be re-used with the same key. I also have minor concerns (like nx in parameters makes no sense), but this is not so important after the first point.
            $endgroup$
            – cutalion
            Feb 20 '17 at 12:56










          • $begingroup$
            object instantiation is free. You have no need to to re-use the single object. the Redis connection is already passed in. you've even named the class RedisLock and not something like RedisLockFactory. The major takeaway here, if you care to take away anything is that your methods are doing too much internally. If you're passing arguments into every single method, that's a code smell. also usually the ! version of a method is called by the non-bang version instead of the other way around. good luck.
            $endgroup$
            – Chris Drappier
            Feb 20 '17 at 16:42











          Your Answer





          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f154936%2fredis-lock-implementation%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          0












          $begingroup$

          Here's a stab at clarifying the intent without changing any of the functionality. I didn't try to run it or anything, so don't hold me to syntax.



          # handles locking and unlocking redis for a particular operation
          class RedisLock
          # thrown when a lock cannot be acquired
          class NotAcquired < StandardError; end

          # since the redis key and ms are used in pretty much every method,
          # might as well go ahead and pass them in the constructor.
          # set defaults here if there are defaults that make sense.
          # make a yardoc comment and describe what these all are.
          def initialize(redis: Redis.current, nx: true, redis_key:, expiration_ms:)
          @redis = redis
          @redis_key = redis_key
          @expiration_ms = expiration_ms
          @nx = nx
          end

          # call it with_lock instead of lock
          # to make it more apparent it accepts a block
          def with_lock!
          raise(NotAcquired, "Could not acquire lock with #args") unless lock
          yield
          unlock(redis_key, random_lock_number)
          true # do you really need to return true here?
          end

          def with_lock
          with_lock!
          rescue NotAcquired
          false
          end

          private

          # set instance variables in the initializer, but never call them directly.
          attr_reader :redis, :redis_key, :expiration_ms, :nx

          def lock
          redis.set(redis_key, random_lock_number, nx: nx, px: expiration_ms)
          end

          # number is a little decieving here when you call `.to_s` at the end.
          # can you use SecureRandom.uuid instead?
          def random_lock_number
          @random_lock_number ||= SecureRandom.random_number(100_000_000_000_000_000).to_s
          end

          # no need for this to be exposed publicly.
          # calling eval directly is usually a bad idea.
          def unlock
          redis.eval(redis_check_and_delete, [redis_key, random_lock_number])
          end

          def redis_check_and_delete
          <<-LUA
          if redis.call('get', KEYS[1]) == KEYS[2] then
          redis.call('del', KEYS[1])
          end
          LUA
          end
          end


          And to call it:



          RedisLock.new(redis_key: 'key', expiration_ms: 10000).with_lock! do_something 





          share|improve this answer











          $endgroup$












          • $begingroup$
            Hi @Chris! Thanks you for the answer! Though I cannot agree with the suggested improvements. The general concern about it is that the new object cannot be re-used with another key. Moreover it even cannot be re-used with the same key. I also have minor concerns (like nx in parameters makes no sense), but this is not so important after the first point.
            $endgroup$
            – cutalion
            Feb 20 '17 at 12:56










          • $begingroup$
            object instantiation is free. You have no need to to re-use the single object. the Redis connection is already passed in. you've even named the class RedisLock and not something like RedisLockFactory. The major takeaway here, if you care to take away anything is that your methods are doing too much internally. If you're passing arguments into every single method, that's a code smell. also usually the ! version of a method is called by the non-bang version instead of the other way around. good luck.
            $endgroup$
            – Chris Drappier
            Feb 20 '17 at 16:42















          0












          $begingroup$

          Here's a stab at clarifying the intent without changing any of the functionality. I didn't try to run it or anything, so don't hold me to syntax.



          # handles locking and unlocking redis for a particular operation
          class RedisLock
          # thrown when a lock cannot be acquired
          class NotAcquired < StandardError; end

          # since the redis key and ms are used in pretty much every method,
          # might as well go ahead and pass them in the constructor.
          # set defaults here if there are defaults that make sense.
          # make a yardoc comment and describe what these all are.
          def initialize(redis: Redis.current, nx: true, redis_key:, expiration_ms:)
          @redis = redis
          @redis_key = redis_key
          @expiration_ms = expiration_ms
          @nx = nx
          end

          # call it with_lock instead of lock
          # to make it more apparent it accepts a block
          def with_lock!
          raise(NotAcquired, "Could not acquire lock with #args") unless lock
          yield
          unlock(redis_key, random_lock_number)
          true # do you really need to return true here?
          end

          def with_lock
          with_lock!
          rescue NotAcquired
          false
          end

          private

          # set instance variables in the initializer, but never call them directly.
          attr_reader :redis, :redis_key, :expiration_ms, :nx

          def lock
          redis.set(redis_key, random_lock_number, nx: nx, px: expiration_ms)
          end

          # number is a little decieving here when you call `.to_s` at the end.
          # can you use SecureRandom.uuid instead?
          def random_lock_number
          @random_lock_number ||= SecureRandom.random_number(100_000_000_000_000_000).to_s
          end

          # no need for this to be exposed publicly.
          # calling eval directly is usually a bad idea.
          def unlock
          redis.eval(redis_check_and_delete, [redis_key, random_lock_number])
          end

          def redis_check_and_delete
          <<-LUA
          if redis.call('get', KEYS[1]) == KEYS[2] then
          redis.call('del', KEYS[1])
          end
          LUA
          end
          end


          And to call it:



          RedisLock.new(redis_key: 'key', expiration_ms: 10000).with_lock! do_something 





          share|improve this answer











          $endgroup$












          • $begingroup$
            Hi @Chris! Thanks you for the answer! Though I cannot agree with the suggested improvements. The general concern about it is that the new object cannot be re-used with another key. Moreover it even cannot be re-used with the same key. I also have minor concerns (like nx in parameters makes no sense), but this is not so important after the first point.
            $endgroup$
            – cutalion
            Feb 20 '17 at 12:56










          • $begingroup$
            object instantiation is free. You have no need to to re-use the single object. the Redis connection is already passed in. you've even named the class RedisLock and not something like RedisLockFactory. The major takeaway here, if you care to take away anything is that your methods are doing too much internally. If you're passing arguments into every single method, that's a code smell. also usually the ! version of a method is called by the non-bang version instead of the other way around. good luck.
            $endgroup$
            – Chris Drappier
            Feb 20 '17 at 16:42













          0












          0








          0





          $begingroup$

          Here's a stab at clarifying the intent without changing any of the functionality. I didn't try to run it or anything, so don't hold me to syntax.



          # handles locking and unlocking redis for a particular operation
          class RedisLock
          # thrown when a lock cannot be acquired
          class NotAcquired < StandardError; end

          # since the redis key and ms are used in pretty much every method,
          # might as well go ahead and pass them in the constructor.
          # set defaults here if there are defaults that make sense.
          # make a yardoc comment and describe what these all are.
          def initialize(redis: Redis.current, nx: true, redis_key:, expiration_ms:)
          @redis = redis
          @redis_key = redis_key
          @expiration_ms = expiration_ms
          @nx = nx
          end

          # call it with_lock instead of lock
          # to make it more apparent it accepts a block
          def with_lock!
          raise(NotAcquired, "Could not acquire lock with #args") unless lock
          yield
          unlock(redis_key, random_lock_number)
          true # do you really need to return true here?
          end

          def with_lock
          with_lock!
          rescue NotAcquired
          false
          end

          private

          # set instance variables in the initializer, but never call them directly.
          attr_reader :redis, :redis_key, :expiration_ms, :nx

          def lock
          redis.set(redis_key, random_lock_number, nx: nx, px: expiration_ms)
          end

          # number is a little decieving here when you call `.to_s` at the end.
          # can you use SecureRandom.uuid instead?
          def random_lock_number
          @random_lock_number ||= SecureRandom.random_number(100_000_000_000_000_000).to_s
          end

          # no need for this to be exposed publicly.
          # calling eval directly is usually a bad idea.
          def unlock
          redis.eval(redis_check_and_delete, [redis_key, random_lock_number])
          end

          def redis_check_and_delete
          <<-LUA
          if redis.call('get', KEYS[1]) == KEYS[2] then
          redis.call('del', KEYS[1])
          end
          LUA
          end
          end


          And to call it:



          RedisLock.new(redis_key: 'key', expiration_ms: 10000).with_lock! do_something 





          share|improve this answer











          $endgroup$



          Here's a stab at clarifying the intent without changing any of the functionality. I didn't try to run it or anything, so don't hold me to syntax.



          # handles locking and unlocking redis for a particular operation
          class RedisLock
          # thrown when a lock cannot be acquired
          class NotAcquired < StandardError; end

          # since the redis key and ms are used in pretty much every method,
          # might as well go ahead and pass them in the constructor.
          # set defaults here if there are defaults that make sense.
          # make a yardoc comment and describe what these all are.
          def initialize(redis: Redis.current, nx: true, redis_key:, expiration_ms:)
          @redis = redis
          @redis_key = redis_key
          @expiration_ms = expiration_ms
          @nx = nx
          end

          # call it with_lock instead of lock
          # to make it more apparent it accepts a block
          def with_lock!
          raise(NotAcquired, "Could not acquire lock with #args") unless lock
          yield
          unlock(redis_key, random_lock_number)
          true # do you really need to return true here?
          end

          def with_lock
          with_lock!
          rescue NotAcquired
          false
          end

          private

          # set instance variables in the initializer, but never call them directly.
          attr_reader :redis, :redis_key, :expiration_ms, :nx

          def lock
          redis.set(redis_key, random_lock_number, nx: nx, px: expiration_ms)
          end

          # number is a little decieving here when you call `.to_s` at the end.
          # can you use SecureRandom.uuid instead?
          def random_lock_number
          @random_lock_number ||= SecureRandom.random_number(100_000_000_000_000_000).to_s
          end

          # no need for this to be exposed publicly.
          # calling eval directly is usually a bad idea.
          def unlock
          redis.eval(redis_check_and_delete, [redis_key, random_lock_number])
          end

          def redis_check_and_delete
          <<-LUA
          if redis.call('get', KEYS[1]) == KEYS[2] then
          redis.call('del', KEYS[1])
          end
          LUA
          end
          end


          And to call it:



          RedisLock.new(redis_key: 'key', expiration_ms: 10000).with_lock! do_something 






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Feb 20 '17 at 7:55

























          answered Feb 20 '17 at 7:50









          Chris DrappierChris Drappier

          255129




          255129











          • $begingroup$
            Hi @Chris! Thanks you for the answer! Though I cannot agree with the suggested improvements. The general concern about it is that the new object cannot be re-used with another key. Moreover it even cannot be re-used with the same key. I also have minor concerns (like nx in parameters makes no sense), but this is not so important after the first point.
            $endgroup$
            – cutalion
            Feb 20 '17 at 12:56










          • $begingroup$
            object instantiation is free. You have no need to to re-use the single object. the Redis connection is already passed in. you've even named the class RedisLock and not something like RedisLockFactory. The major takeaway here, if you care to take away anything is that your methods are doing too much internally. If you're passing arguments into every single method, that's a code smell. also usually the ! version of a method is called by the non-bang version instead of the other way around. good luck.
            $endgroup$
            – Chris Drappier
            Feb 20 '17 at 16:42
















          • $begingroup$
            Hi @Chris! Thanks you for the answer! Though I cannot agree with the suggested improvements. The general concern about it is that the new object cannot be re-used with another key. Moreover it even cannot be re-used with the same key. I also have minor concerns (like nx in parameters makes no sense), but this is not so important after the first point.
            $endgroup$
            – cutalion
            Feb 20 '17 at 12:56










          • $begingroup$
            object instantiation is free. You have no need to to re-use the single object. the Redis connection is already passed in. you've even named the class RedisLock and not something like RedisLockFactory. The major takeaway here, if you care to take away anything is that your methods are doing too much internally. If you're passing arguments into every single method, that's a code smell. also usually the ! version of a method is called by the non-bang version instead of the other way around. good luck.
            $endgroup$
            – Chris Drappier
            Feb 20 '17 at 16:42















          $begingroup$
          Hi @Chris! Thanks you for the answer! Though I cannot agree with the suggested improvements. The general concern about it is that the new object cannot be re-used with another key. Moreover it even cannot be re-used with the same key. I also have minor concerns (like nx in parameters makes no sense), but this is not so important after the first point.
          $endgroup$
          – cutalion
          Feb 20 '17 at 12:56




          $begingroup$
          Hi @Chris! Thanks you for the answer! Though I cannot agree with the suggested improvements. The general concern about it is that the new object cannot be re-used with another key. Moreover it even cannot be re-used with the same key. I also have minor concerns (like nx in parameters makes no sense), but this is not so important after the first point.
          $endgroup$
          – cutalion
          Feb 20 '17 at 12:56












          $begingroup$
          object instantiation is free. You have no need to to re-use the single object. the Redis connection is already passed in. you've even named the class RedisLock and not something like RedisLockFactory. The major takeaway here, if you care to take away anything is that your methods are doing too much internally. If you're passing arguments into every single method, that's a code smell. also usually the ! version of a method is called by the non-bang version instead of the other way around. good luck.
          $endgroup$
          – Chris Drappier
          Feb 20 '17 at 16:42




          $begingroup$
          object instantiation is free. You have no need to to re-use the single object. the Redis connection is already passed in. you've even named the class RedisLock and not something like RedisLockFactory. The major takeaway here, if you care to take away anything is that your methods are doing too much internally. If you're passing arguments into every single method, that's a code smell. also usually the ! version of a method is called by the non-bang version instead of the other way around. good luck.
          $endgroup$
          – Chris Drappier
          Feb 20 '17 at 16:42

















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f154936%2fredis-lock-implementation%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          名間水力發電廠 目录 沿革 設施 鄰近設施 註釋 外部連結 导航菜单23°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.7113923°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.71139計畫概要原始内容臺灣第一座BOT 模式開發的水力發電廠-名間水力電廠名間水力發電廠 水利署首件BOT案原始内容《小檔案》名間電廠 首座BOT水力發電廠原始内容名間電廠BOT - 經濟部水利署中區水資源局

          Prove that NP is closed under karp reduction?Space(n) not closed under Karp reductions - what about NTime(n)?Class P is closed under rotation?Prove or disprove that $NL$ is closed under polynomial many-one reductions$mathbfNC_2$ is closed under log-space reductionOn Karp reductionwhen can I know if a class (complexity) is closed under reduction (cook/karp)Check if class $PSPACE$ is closed under polyonomially space reductionIs NPSPACE also closed under polynomial-time reduction and under log-space reduction?Prove PSPACE is closed under complement?Prove PSPACE is closed under union?

          Is my guitar’s action too high? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)Strings too stiff on a recently purchased acoustic guitar | Cort AD880CEIs the action of my guitar really high?Μy little finger is too weak to play guitarWith guitar, how long should I give my fingers to strengthen / callous?When playing a fret the guitar sounds mutedPlaying (Barre) chords up the guitar neckI think my guitar strings are wound too tight and I can't play barre chordsF barre chord on an SG guitarHow to find to the right strings of a barre chord by feel?High action on higher fret on my steel acoustic guitar