Closed romank0 closed 3 weeks ago
Out of curiosity, does the same happen with psycopg 3 too?
In the real life scenarios where this was spotted we still use psycopg2. I haven't tried the above script on psycopg3, but from the source code I can see it has the same issue that notifications are not fetched after libpq.PQgetResult
. But I can't say I can follow the code completely. I'll try to test that.
Re psycopg 3: it is not an apple to apple comparison because the API is quite different. And more importantly it seems that psycopg 3 does not allow to use the connection to execute queries while iterating over notifications or from the notification processing callback (if I try to do that the execute
is blocked indefinitely).
Because of this I can't do a proper comparison but if we are talking about the commit
operation specifically I can see from the stacktrace it does process notifications properly.
The workaround that works is:
while True:
if select.select([conn],[],[],1) == ([],[],[]):
print("Timeout")
else:
need_to_poll = True
while need_to_poll:
need_to_poll = False
conn.poll()
while conn.notifies:
notify = conn.notifies.pop(0)
print("Got NOTIFY:", notify.pid, notify.channel, notify.payload)
# some processing that updates the DB based on the notify content
conn.commit()
need_to_poll = True
Fixed by merging #1728. Thank you very much for reporting the problem and providing a solution!
I will wrap a release in the next few days.
The issue
I'm using the recommended way to receive async notifications that is:
select.select
to wait on the data available on the connectionconnection.poll
connection.notifies
list. Each notification is processed in a transactionBasically the code is almost the copy and paste from the documentation except that I do not use autocommit because I manually manage transactions:
The problem is that sometimes (specifically when the notification is received during the
commit
) this code gets into the state that:select.select
shows)poll
on the connection new notifications will be added tonotifies
listBecause of this the code loops on the
select.select
and some notifications processing is delayed until the new notification comes in later.My interpretation of what happens
I've tracked this down to the problem in the
pq_commit
and/orpq_execute_command_locked
. Namely, according to pqlib documentation:pq_execute_command_locked
does invokePQexec
and that according to my understanding reads up the data from the socket but thenPQnotifies
are not checked inpq_commit
. So the followup invocation ofselect
shows there is not more data to read and there is no progress in the listen loop.Most probably this is not the only place this happens. For example in
pq_get_result_async
I can see that notifications are checked before executingPQgetResult
but according to pqlib docs above that should happen after.The script reproducing the issue.