Skip to content
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

Add API for receiving asynchronous notices #147

Merged
merged 4 commits into from
Jul 5, 2017

Conversation

vitaly-burovoy
Copy link
Contributor

Per request #144.

It seems I implemented it long time ago, but did not have enough time to finalize it as a PR.
I think a single callback per connection is enough, therefore API has just set_notice_callback instead of add_notice_callback and remove_notice_callback.

P.S.: Here is also two minor commits small enough to create separated PRs.

@1st1
Copy link
Member

1st1 commented May 26, 2017

We already have add_lustener API, so add_notice_callback is the way to go.

@vitaly-burovoy
Copy link
Contributor Author

I've just replaced the function to add_notice_callback and added remove_notice_callback.

@elprans elprans self-requested a review May 26, 2017 20:34
# Ignore new unknown fields
pass

self.connection._notice(message)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A subclass of PostgresMessage should be returned here instead of a plain dict.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that way, but why don't pass just a dict?
It is easier for logging (people don't need to iterate over an instance of a class), and callbacks don't get anything except a message consists of fields and values.

PostgresMessage is designed for exceptions, where it is reasonable to have all known fields as attributes, notices are lightweight, used at specified places (callbacks) and don't need so complex creation process (and reverse process -- iteration via attributes to create a dict to be logged).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A simple class is not much "heavier" than a dict. Furthermore, notices should be a rare occurrence (compared to Notify). I don't really think that the ability to enumerate fields is all that useful. On the other hand, if notices are instances of PostgresNotice object, we can make its __str__ default to message and provide access to the message dict via the as_dict() method. IMO, it's a much nicer interface than a plain dict.

Copy link
Member

@elprans elprans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but please make it so that the notification callback receives an instance of PostgresMessage.

@@ -126,6 +127,24 @@ def __init__(self, protocol, transport, loop,
del self._listeners[channel]
await self.fetch('UNLISTEN {}'.format(channel))

def add_notice_callback(self, callback):
"""Set a callback to be used when asyncronous NoticeResponse is received
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first line of the docstring should be a complete sentence describing what the method does.

Then an empty new line.

Then you can add more paragraphs.

@@ -909,6 +930,25 @@ def _cancel_current_command(self, waiter):

self._loop.create_task(cancel())

def _notice(self, message):
# `self._notice_cb` is checked internally and passed here as the `cb`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a 'period' at the end of comment sentences. Also the comment looks outdated.

@@ -821,13 +840,15 @@ def is_closed(self):
self._listeners = {}
self._aborted = True
await self._protocol.close()
self._notice_cb_set = set()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rename it to _notice_callbacks.

@@ -909,6 +930,25 @@ def _cancel_current_command(self, waiter):

self._loop.create_task(cancel())

def _notice(self, message):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rename this to _schedule_notice_callbacks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disagree. They are called immediately, there is no schedule process.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Well, you should use loop.call_soon anyways. We never want to call callback right away.

# Ignore new unknown fields
pass

self.connection._notice(message)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1


for cb in self._notice_cb_set:
try:
cb(con_ref, message)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use loop.call_soon here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we'll update notify to use call_soon in a separate PR. That's something that we just oversaw.

Sometimes it is useful to get all non-None members, usually for logging.
Do it in a base class to avoid copy-pasting in users' code.
@1st1
Copy link
Member

1st1 commented Jun 30, 2017

Hi @vitaly-burovoy! Are you going to continue working on this PR? We'll be releasing a new version of asyncpg soon.

@vitaly-burovoy vitaly-burovoy force-pushed the notices branch 2 times, most recently from 6934885 to 844804a Compare July 5, 2017 03:31
@vitaly-burovoy
Copy link
Contributor Author

I committed requested changes (I hope I did not forget something), but Travis could not check it because it failed installing Python in OSX (if I understand its log correctly).

What should I do now?

@1st1
Copy link
Member

1st1 commented Jul 5, 2017

I'm merging the PR although there's some work left; we'll open separate PRs to address it.

@1st1 1st1 merged commit 1b1893d into MagicStack:master Jul 5, 2017
@vitaly-burovoy
Copy link
Contributor Author

Thank you very much!

@vitaly-burovoy vitaly-burovoy deleted the notices branch December 5, 2017 04:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants