Replies: 2 comments
-
I didn't notice anything for sure, but I suspect there is some sort of race condition.
Beyond that though, I would recommend separating the listen to channel from wait for notification steps. I think it is that coupling that makes this hard to reason about. Even simpler would be to avoid adding listen channels after the process is started. That is the approach I took for my own listener (https://github.com/jackc/pgxlisten -- I use in it production -- but not publicized because I want freedom to change or abandon it at will without worrying about the impact to others -- so maybe take more as source of ideas than importing it directly). |
Beta Was this translation helpful? Give feedback.
-
I recently had a similar When you cancel that context, a pgx-internal goroutine needs to detect it, set a deadline on the underlying connection, and then Postgres has to respond to the deadline. Until My situation was something like this, where I was trying to combine func listenUntilError(ctx context.Context, conn *pgx.Conn, external chan struct{}) error {
for {
event, err := waitForEvent(ctx, conn, external)
if err != nil {
return err
}
// send event to subscribers
}
}
func waitForEvent(ctx context.Context, conn *pgx.Conn, external chan struct{}) (Event, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel() // cancel WaitForNotification if we get an external event
type waitResult struct {
n *pgconn.Notification
err error
}
result := make(chan waitResult, 1)
go func() {
n, err := conn.WaitForNotification(ctx)
result <- waitResult{n, err}
}()
select {
case <-external:
return Event{Payload: "external"}, nil
case r := <-result:
if r.err != nil {
return Event{}, r.err
}
return Event{Payload: r.n.Payload}, nil
}
} If an external event arrived first, I cancelled the context, but did not wait for I fixed the issue by combining the two functions in a way that removed the need to cancel the context. There's now one loop in a goroutine calling I'm not sure if this is the same problem, but the code in the original post also cancels the context in a |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
In my application, I need several goroutines to
LISTEN
for severalNOTIFY
channels.Based on the discussion in #735, #195, and a few other places, here's what I wrote:
Then I call it like this:
The problem is that the second call to
Subscribe
throws aconn busy
error. From the logs, I can see that the first call toSubscribe
properly callsLISTEN notify_live_media
, and the second call theSubscribe
properly cancels the listener, then callsLISTEN notify_live_media
which works properly followed byLISTEN notify_live_messages
which returns the error.As far as I can tell, the calls to
rawConn.Exec()
are being executed sequentially, and I see in the source thatExec
callsexecSimpleProtocol()
which both locks the connection (insidepgConn.Exec()
) and also unlocks the connection (insidemrr.Close()
).Why can't I run multiple
LISTEN
queries in a loop? What am I missing?Beta Was this translation helpful? Give feedback.
All reactions