Repository navigation
feat: support LISTEN/NOTIFY - #512
Open
thuongtamduy wants to merge 1 commit into
Open
thuongtamduy wants to merge 1 commit into
thuongtamduy wants to merge 1 commit into
Conversation
The connection now handles NotificationResponse messages in every state. Before, a notification received by a session that ran `LISTEN` made the next query throw "Unexpected simple query message: A" (or "prepared query") and left the rest of the response in the socket, so the following query received the result of the previous one. Notifications received during a query are dispatched to the listeners without affecting its result. While listeners are registered, the connection keeps a read in progress when no query is running so notifications are received while idle; a query that starts takes that read over before writing, so there is a single reader of the socket at any time. Adds `Client.listen(channel, listener)` and `Client.unlisten(channel, listener?)`. Channel names are quoted as identifiers. Channels are listened to again after a reconnection and listeners are dropped on `end()`. Closes denodrivers#39 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: support LISTEN/NOTIFY
Closes #39
Problem
The driver does not handle
NotificationResponse('A') messages. Once asession has run
LISTEN, any notification sent to it breaks the connection:There is also no way to receive notifications: the socket is only read while a
query is running.
Changes
NotificationResponseis parsed (parseNotificationMessage) and handled inboth the simple and the extended query loops. A notification received in the
middle of a query is passed to the listeners and does not affect the query
result. This alone fixes the out-of-sync connection above.
connection keeps one message read in progress, so notifications are received
while the client is idle. A query takes that read over right after acquiring
the query lock and before writing anything, so there is only ever one reader
of the socket and the response can't be consumed by the idle reader. Idle
messages that are not notifications, notices or parameter statuses (e.g. a
FATAL error when the backend is terminated) close the connection, like any
other connection loss.
UNLISTENruns as a normal query (takingover the idle read) and no new read is started, so the process can exit
without calling
end()."doubled), never concatenated as rawSQL.
the next query runs.
Client.end()drops all listeners.break the message loop.
API
Available on
Clientonly. Pool clients are shared, so a dedicated clientshould be used for listening.
New exported types:
Notification({ channel, payload, processId }) andNotificationListener.listen/unlistenthrow if the client is locked by atransaction, the same as
queryArray/queryObject. The channel name is usedliterally (like a quoted identifier), so it has to match the name passed to
pg_notifyexactly. The docs (docs/README.md) have a new "Notifications"section.
Tests
New
tests/notification_test.ts(11 tests):query, or the one after it. These two tests use plain
LISTENand fail onmainwith the errors above.pg_sleep) doesn't change its resultor the next query's result
unlistenof one listener and of a whole channel (checked withpg_listening_channels());, non-ASCII), Unicode and empty payloads,empty channel rejected
NOTIFYin a transaction is only delivered after commitlistenis rejected while a transaction holds the client(
pg_terminate_backend) and the client reconnectsend()drops the listenersResults with
docker compose run tests/no_check_tests/doc_tests:main: 243 passed, 3 failedmain: theHandles parameter status ...tests use theHongKongtime zone, which thecurrent
postgres:14image no longer accepts.deno fmt --checkanddeno lintpass (Deno 2.2.11, the version in theDockerfile)
The new tests also pass against PostgreSQL 18.