Re: NOTIFY in asynchronous mode

From: Jan Urbański <wulczer(at)wulczer(dot)org>
To: Tobias Oberstein <tobias(dot)oberstein(at)tavendo(dot)de>
Cc: Daniele Varrazzo <daniele(dot)varrazzo(at)gmail(dot)com>, "psycopg(at)postgresql(dot)org" <psycopg(at)postgresql(dot)org>
Subject: Re: NOTIFY in asynchronous mode
Date: 2011-11-05 11:51:46
Message-ID: 4EB52352.2040802@wulczer.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: psycopg

On 05/11/11 11:54, Tobias Oberstein wrote:
> -- Original message -----
>>> What would be provided to the callback?
>>>
>>> Channel (from NOTIFIY), Payload (from NOTIFIY), Connection (txpostgres)
>> ?
>>
>> Probably simply the psycopg2 Notify object.
>
> Ok, fine also.
>
> And not the Connection object on which it was received? Ok, maybe it's
> not needed: When I want to do some db stuff within the callback, should
> not make a difference on what connection I do that.

You would register the callback on the Connection object, so you could
tell it which connection it will get registered on beforehand.

> Few other design Qs:
>
> Is it possible to UNLISTEN?

Sure, because you'd call both LISTEN and UNLISTEN as SQL statements with
runQuery.

> Or unregister a callback on a channel? Or set it to None?
>
> Are callbacks for channels registered "globally" or per connection?

The callbacks would be registered per connection, since it's the
connection who receives notifications.

> Can there be only one callback at most registered per channel?

Channel handling would be entirely up to the client. Here's a quick
example of how it could work (based on the patch I previously mentioned
from Jan Pobrislo, with a slightly changed callback API):

from twisted.python import log
from twisted.python.util import println

class NotifyObserver(object):

def __init__(self, conn):
self.conn = conn

def __call__(self, notify):
if notify.channel == 'channel1':
println('got notify on channel 1, unlistening and removing')
self.conn.removeNotifyObserver(self)
d = conn.runQuery('UNLISTEN *')
d.addCallback(lambda _: println('unlistened'))
d.addErrback(log.err)
else:
println('got some other notify')

# conn is a txpostgres Connection
observer = NotifyObserver(conn)
# any number of different callables can be registered, here we just
register one
conn.addNotifyObserver(observer)

d = conn.runQuery('LISTEN channel1')
d.addCallback(lambda _: conn.runQuery('LISTEN channel2'))
d.addCallback(lanbda _: println('listening')

# then, after the program prints "listening" execute from psql in
another session
=$ NOTIFY channel2;
=$ NOTIFY channel2;
=$ NOTIFY channel1;
=$ NOTIFY channel2;

# which would yield the following from the running program
"got some other notify"
"got some other notify"
"got notify on channel 1, unlistening and removing"

# note that after a notify on channel1 is received, the observer is gone
and no more notifies are processed

I think that's a reasonably simple API and one that allows you to do
anything you want without introducing some extra interfaces that notify
observers have to implement, just requiring that they are callable.

Cheers,
Jan

In response to

Responses

Browse psycopg by date

  From Date Subject
Next Message Tobias Oberstein 2011-11-05 12:37:39 Re: NOTIFY in asynchronous mode
Previous Message Tobias Oberstein 2011-11-05 10:54:20 Re: NOTIFY in asynchronous mode