title: Redis: How to ensure both concurrency and atomic for shopping case?
body: <p>Suppose that <code>food_dict</code> is <code>dictionary</code> to store items in <em>shopping cart</em>, </p>
  
  <pre><code>{&lt;food_id&gt;:&lt;count&gt;}
  </code></pre>
  
  <p>(<em>One cart may contain multiple foods</em>)</p>
  
  <p>I have stored <code>food</code> in <code>redis</code> in advance:</p>
  
  <pre><code>r.hset('food:&lt;food_id&gt;', {'price': &lt;price&gt;, 'stock': &lt;stock&gt;})
  </code></pre>
  
  <p>When making order of <code>cart</code>, I have to ensure that <strong><code>stock</code> is larger than <code>count</code></strong>.</p>
  
  <p>The basic implement:</p>
  
  <pre><code>for k,v in food_dict.iteritems():
      _stock = int(redis_db.hget('food:' + str(k), 'stock'))
      if v &gt; _stock:
         # I have to rollback the decrement of stock
         break
      else:
         redis_db.hset('food:' + str(k), 'stock', _stock - v)
  </code></pre>
  
  <p>To <code>rollback</code>, <code>pipeline</code> is needed.</p>
  
  <pre><code>    pipe = redis_db.pipeline()
      for k, v in food_dict.iteritems():
          _stock = int(redis_db.hget('food:' + str(k), 'stock'))
          if v &gt; _stock:
              return
          else:
              pipe.hset('food:' + str(k), 'stock', _stock - v)
      pipe.execute()
  </code></pre>
  
  <p>For single client, the code above can well-done. When it comes to concurrency:</p>
  
  <pre><code>with redis_db.pipleline() as pipe:
      while 1:
          try:
              pipe.watch(['food:' + str(k) for k in food_dict])
              stock_dict = {}
              for k in food_dict:
                  _stock = pipe.hget('food:' + str(k), 'stock')
                  stock_dict[k] = _stock
              pipe.multi()
              for k, v in food_dict.iteritems():
                  if v &gt; stock_dict[k]:
                      break
                  else:
                      pipe.hset('food:' + str(k), 'stock', stock_dict[k] - v)
              pipe.execute()
              break
          except WathchError:
              continue
          finally:
              pipe.reset()
  </code></pre>
  
  <p>Can this code guarantee that order can be make <strong>only when stock is larger than count</strong>?</p>