-
Notifications
You must be signed in to change notification settings - Fork 128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
reader: by default, archive failed messages to disk #135
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,8 @@ | |
import cgi | ||
import warnings | ||
import inspect | ||
import datetime | ||
import os.path | ||
|
||
try: | ||
import simplejson as json | ||
|
@@ -131,6 +133,8 @@ def process_message(message): | |
|
||
:param max_backoff_duration: the maximum time we will allow a backoff state to last in seconds | ||
|
||
:param data_path: the directory failed messages will be archived to after ``max_tries`` | ||
|
||
:param \*\*kwargs: passed to :class:`nsq.AsyncConn` initialization | ||
""" | ||
def __init__( | ||
|
@@ -149,6 +153,7 @@ def __init__( | |
lookupd_poll_jitter=0.3, | ||
lookupd_connect_timeout=1, | ||
lookupd_request_timeout=2, | ||
data_path=None, | ||
**kwargs): | ||
super(Reader, self).__init__(**kwargs) | ||
|
||
|
@@ -161,6 +166,7 @@ def __init__( | |
assert isinstance(lookupd_poll_jitter, float) | ||
assert isinstance(lookupd_connect_timeout, int) | ||
assert isinstance(lookupd_request_timeout, int) | ||
assert isinstance(data_path, (str, unicode, None.__class__)) | ||
|
||
assert lookupd_poll_jitter >= 0 and lookupd_poll_jitter <= 1 | ||
|
||
|
@@ -222,6 +228,7 @@ def __init__( | |
|
||
self.redist_periodic = None | ||
self.query_periodic = None | ||
self.data_path = data_path | ||
|
||
def _run(self): | ||
assert self.message_handler, "you must specify the Reader's message_handler" | ||
|
@@ -702,14 +709,31 @@ def process_message(self, message): | |
|
||
def giving_up(self, message): | ||
""" | ||
Called when a message has been received where ``msg.attempts > max_tries`` | ||
Called when a message has been received where ``msg.attempts > max_tries``. | ||
|
||
Failed messages will be archived to ``$data_path/$channel_$topic/%Y%m%d-%H%M%S-%f_$sequence.failed.msg`` | ||
|
||
This is useful to subclass and override to perform a task (such as writing to disk, etc.) | ||
This is useful to subclass and override to perform a custom task (such as writing to disk, etc.) | ||
|
||
:param message: the :class:`nsq.Message` received | ||
""" | ||
logger.warning('[%s] giving up on message %s after %d tries (max:%d) %r', | ||
self.name, message.id, message.attempts, self.max_tries, message.body) | ||
|
||
self.failed_count += 1 | ||
|
||
path = os.path.join(self.data_path or "", self.topic + '_' + self.channel) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably use a separator that isn't a valid character for a topic/channel. Perhaps the channel should just be a real subdir? |
||
if not os.path.exists(path): | ||
os.makedirs(path) | ||
|
||
date_str = datetime.datetime.utcnow().strftime("%Y%m%d-%H%M%S-%f") | ||
filename = "%s_%d.failed.msg" % (date_str, self.failed_count) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (too) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i have mixed feelings. In some ways it could augment however since I chose to calculate the filename and include that in the log line as an alternative way a) raise awareness of the file archiving and b) link the two. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Fair point, that was the only reason why I thought it would be useful in the filename. |
||
filename = os.path.join(path, filename) | ||
|
||
logging.warning('[%s] giving up on message %s after %d tries (max:%d). Archived to %s %r', | ||
self.name, message.id, message.attempts, self.max_tries, filename, message.body) | ||
|
||
f = open(filename, 'wb') | ||
f.write(message.body + '\n') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure we should append anything to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah... this is a tough one. I'm certainly biased by my own I think there are three basic options a) document and move on, I'm inlined to do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a fan of more options (c) and I suppose that they can still override this method if one doesn't want a newline appended, so let's do (a)? |
||
f.close() | ||
|
||
|
||
def _on_connection_identify_response(self, conn, data, **kwargs): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see where this is being initialized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha. just copy & pasting from my custom
giving_up()
here. I'll try some real validation =)