title: How to prevent race condition when using redis to implement flow control?
body: <p>We have a server that gets cranky if it gets too many users logging in at the same time (meaning less than 7 seconds apart).  Once the users are logged in, there is no problem (one or two logging in at the same time is also not a problem, but when 10-20 try the entire server goes into a death spiral <em>sigh</em>).</p>
  
  <p>I'm attempting to write a page that will hold onto users (displaying an animated countdown etc.) and let them through 7 seconds apart.  The algorithm is simple</p>
  
  <ol>
  <li>fetch the timestamp (t) when the last login happened</li>
  <li>if <code>t+7</code> is in the past start the login and store <code>now()</code> as the new timestamp</li>
  <li>if <code>t+7</code> is in the future, store it as the new timestamp, wait until <code>t+7</code>, then start the login.</li>
  </ol>
  
  <p>A straight forward python/redis implementation would be:</p>
  
  <pre><code>import time, redis
  SLOT_LENGTH = 7  # seconds
  
  now = time.time()
  
  r = redis.StrictRedis()
  
  # lines below contain race condition..
  last_start = float(r.get('FLOWCONTROL') or '0.0')  # 0.0 == time-before-time
  my_start = last_start + SLOT_LENGTH
  r.set('FLOWCONTROL', max(my_start, now))  
  
  wait_period = max(0, my_start - now)
  time.sleep(wait_period)
  
  # .. login
  </code></pre>
  
  <p>The race condition here is obvious, many processes can be at the <code>my_start =</code> line simultaneously.  How can I solve this using redis?</p>
  
  <p>I've tried the redis-py <code>pipeline</code> functionality, but of course that doesn't get an actual value until in the <code>r.get()</code> call...</p>