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.
-
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