Last active
August 29, 2015 14:04
-
-
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?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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