Delegate the notifications handling to the backend

This commit is contained in:
Nicolas Évrard
2025-11-25 13:27:24 +01:00
parent dada23bcb5
commit 4ab7069dab
5 changed files with 25 additions and 13 deletions
+6
View File
@@ -73,6 +73,12 @@ class DatabaseInterface(object):
def estimated_count(self, connection, table):
raise NotImplementedError
def notify(self, connection, channel, payload):
raise NotImplementedError
def get_notifications(self, connection):
raise NotImplementedError
@classmethod
def lock(cls, connection, table):
raise NotImplementedError
@@ -492,6 +492,14 @@ class Database(DatabaseInterface):
cursor.execute(*from_item.select(Count(Literal('*'))))
return cursor.fetchone()[0]
def notify(self, connection, channel, payload):
cursor = connection.cursor()
cursor.execute('NOTIFY "%s", %%s' % channel, (payload,))
def get_notifications(self, connection):
connection.poll()
return connection.notifies
@classmethod
def lock(cls, connection, table):
cursor = connection.cursor()
+5 -5
View File
@@ -154,9 +154,9 @@ class LongPollingBus:
selector.register(conn, selectors.EVENT_READ)
while cls._queues[pid, database]['timeout'] > now:
selector.select(timeout=config.getint('bus', 'select_timeout'))
conn.poll()
while conn.notifies:
notification = conn.notifies.pop()
notifications = db.get_notifications(conn)
while notifications:
notification = notifications.pop()
payload = json.loads(
notification.payload,
object_hook=JSONDecoder())
@@ -200,13 +200,13 @@ class LongPollingBus:
logger.info("database backend does not support channels")
return
cursor = transaction.connection.cursor()
message['message_id'] = str(uuid.uuid4())
payload = json.dumps({
'channel': channel,
'message': message,
}, cls=JSONEncoder, separators=(',', ':'))
cursor.execute('NOTIFY "%s", %%s' % cls._channel, (payload,))
transaction.database.notify(
transaction.connection, cls._channel, payload)
logger.debug(
"publish %r to '%s' on '%s'",
message, channel, transaction.database.name)
+5 -6
View File
@@ -308,9 +308,8 @@ class MemoryCache(BaseCache):
# The count computed as
# 8000 (max notify size) / 64 (max name data len)
for sub_reset in grouped_slice(reset, 125):
cursor.execute(
'NOTIFY "%s", %%s' % cls._channel,
(json.dumps(list(sub_reset), separators=(',', ':')),))
database.notify(transaction.connection, cls._channel,
json.dumps(list(sub_reset), separators=(',', ':')))
else:
connection = database.get_connection(
readonly=False, autocommit=True)
@@ -429,9 +428,9 @@ class MemoryCache(BaseCache):
while cls._local.listeners.get(dbname) == current_thread:
selector.select(
timeout=config.getint('cache', 'select_timeout'))
conn.poll()
while conn.notifies:
notification = conn.notifies.pop()
notifications = database.get_notifications(conn)
while notifications:
notification = notifications.pop()
payload = notification.payload
if payload and payload.startswith(REFRESH_POOL_MSG):
remote_id = payload[len(REFRESH_POOL_MSG) + 1:]
+1 -2
View File
@@ -61,7 +61,6 @@ class Queue(ModelSQL):
def push(cls, name, data, scheduled_at=None, expected_at=None):
transaction = Transaction()
database = transaction.database
cursor = transaction.connection.cursor()
with without_check_access():
record, = cls.create([{
'name': name,
@@ -70,7 +69,7 @@ class Queue(ModelSQL):
'expected_at': expected_at,
}])
if database.has_channel():
cursor.execute('NOTIFY "%s"', (cls.__name__,))
database.notify(transaction.connection, cls.__name__, '')
if not config.getboolean('queue', 'worker', default=False):
transaction.tasks.append(record.id)
return record.id