Skip to content

Instantly share code, notes, and snippets.

@wolever
Last active August 29, 2015 14:04
Show Gist options
  • Save wolever/3dc2d3af7227b6f8f79f to your computer and use it in GitHub Desktop.
Save wolever/3dc2d3af7227b6f8f79f to your computer and use it in GitHub Desktop.
What I'm currently calling the "Notice Board pattern". Is this already a thing?
"""
The Notice Board pattern: returns the most recent value associated with a key,
or blocks waiting for a new value if the current value has already been seen.
History is not stored; only the most recent value is available.
The physical analogy is a notice board like you might see at a train station:
when you arrive at the station you can glance at the board to check the current
departure time for your train, or you can stand around watching the board
waiting for the inevitable message that your train has been delayed.
API:
NoticeBoard.notify(key, value) => timestamp:
Sets a notification and returns the notification's timestamp.
NoticeBoard.watch(key, last=None) => (timestamp, value)
Returns a ``(timestamp, value)`` tuple where the ``timestamp`` is
guaranteed to be greater than the value of ``last``. Will return
immidiately if a value is available, or block waiting for a new
notification to become available.
Example: a long-running job publishes progress notificaitons which are
displayed to a user by a separate process.
$ cat long_running_job.py
from noticeboard import NoticeBoard
board = NoticeBoard("job-status")
widgets_processed = 0
while True:
process_widget()
widgets_processed += 1
board.notify("widgets-processed", widgets_processed)
$ cat progress_monitor.py
from noticeboard import NoticeBoard
board = NoticeBoard("job-status")
last = None
while True:
last, widgets_processed = board.watch("widgets-processed", last=last)
print "Widgets processed so far:", widgets_processed
"""
class NoticeBoard(object):
""" An example, un-tested, Notice Board implementation using Redis """
def __init__(self, name):
self.name = name
self.redis = get_redis()
def notify(self, key, value):
""" Sets a notification. Note: not at all concurrency safe. """
timestamp = time.time()
key = "%s:%s" %(self.name, key)
value = "%s:%s" %(timestamp, value)
self.redis.set(key, value)
self.redis.broadcast(key, value)
return timestamp
def watch(self, key, last=None):
last = last or 0
key = "%s:%s" %(self.name, key)
pubsub = self.redis.subscribe(key)
cur_key_val = self.redis.get(key) or ""
while True:
timestamp_str, _, value = cur_key_val.partition(":")
timestamp = float(timestamp_str or "0")
if timestamp > last:
return (timestamp, value)
cur_key_val = pubsub.wait()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment