generator.py 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. import time
  2. import logging
  3. import tornado.web
  4. EPOCH_TIMESTAMP = 550281600000
  5. class Generator(object):
  6. def __init__(self, dc, worker):
  7. self.dc = dc
  8. self.worker = worker
  9. self.node_id = ((dc & 0x03)<< 8) | (worker & 0xff)
  10. self.last_timestamp = EPOCH_TIMESTAMP
  11. self.sequence = 0
  12. self.sequence_overload = 0
  13. self.errors = 0
  14. self.generated_ids = 0
  15. def get_next_id(self):
  16. curr_time = int(time.time() * 1000)
  17. if curr_time < self.last_timestamp:
  18. # stop handling requests til we've caught back up
  19. self.errors += 1
  20. raise tornado.web.HTTPError(500, 'Clock went backwards! %d < %d' % (curr_time, self.last_timestamp))
  21. if curr_time > self.last_timestamp:
  22. self.sequence = 0
  23. self.last_timestamp = curr_time
  24. self.sequence += 1
  25. if self.sequence > 4095:
  26. # the sequence is overload, just wait to next sequence
  27. logging.warning('The sequence has been overload')
  28. self.sequence_overload += 1
  29. time.sleep(0.001)
  30. return self.get_next_id()
  31. generated_id = ((curr_time - EPOCH_TIMESTAMP) << 22) | (self.node_id << 12) | self.sequence
  32. self.generated_ids += 1
  33. return generated_id
  34. @property
  35. def stats(self):
  36. return {
  37. 'dc': self.dc,
  38. 'worker': self.worker,
  39. 'timestamp': int(time.time()*1000), # current timestamp for this worker
  40. 'last_timestamp': self.last_timestamp, # the last timestamp that generated ID on
  41. 'sequence': self.sequence, # the sequence number for last timestamp
  42. 'sequence_overload': self.sequence_overload, # the number of times that the sequence is overflow
  43. 'errors': self.errors, # the number of times that clock went backward
  44. }