-
Notifications
You must be signed in to change notification settings - Fork 909
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds support for the PostgreSQL LISTEN/NOTIFY mechanism by adding two new user-exposed interfaces: - ListenerConn is a low level interface which establishes a connection to a PostgreSQL server and only knows how to execute simple queries and wait for notifications. This interface does not know how to reconnect, and does not maintain a list of the channels it is listening on. Its use is discouraged. - Listener is the higher-level interface which uses ListenerConn underneath to provide a simpler to use interface, supporting automatic reconnection. In order to do that, it also maintains a list of channels it is already listening on. Significant contributions and ideas from Tommie Gannert. Ideas and valuable feedback from Kamil Kisiel, Maciek Sakrejda and Paul Hammond.
- Loading branch information
Showing
6 changed files
with
1,404 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* | ||
Below you will find a self-contained Go program which uses the LISTEN / NOTIFY | ||
mechanism to avoid polling the database while waiting for more work to arrive. | ||
// | ||
// You can see the program in action by defining a function similar to | ||
// the following: | ||
// | ||
// CREATE OR REPLACE FUNCTION public.get_work() | ||
// RETURNS bigint | ||
// LANGUAGE sql | ||
// AS $$ | ||
// SELECT CASE WHEN random() >= 0.2 THEN int8 '1' END | ||
// $$ | ||
// ; | ||
package main | ||
import ( | ||
"github.com/lib/pq" | ||
"database/sql" | ||
"fmt" | ||
"time" | ||
) | ||
func doWork(db *sql.DB, work int64) { | ||
// work here | ||
} | ||
func getWork(db *sql.DB) { | ||
for { | ||
// get work from the database here | ||
var work sql.NullInt64 | ||
err := db.QueryRow("SELECT get_work()").Scan(&work) | ||
if err != nil { | ||
fmt.Println("call to get_work() failed: ", err) | ||
time.Sleep(10 * time.Second) | ||
continue | ||
} | ||
if !work.Valid { | ||
// no more work to do | ||
fmt.Println("ran out of work") | ||
return | ||
} | ||
fmt.Println("starting work on ", work.Int64) | ||
go doWork(db, work.Int64) | ||
} | ||
} | ||
func waitForNotification(l *pq.Listener) { | ||
for { | ||
select { | ||
case <-l.Notify: | ||
fmt.Println("received notification, new work available") | ||
return | ||
case <-time.After(90 * time.Second): | ||
go func() { | ||
l.Ping() | ||
}() | ||
// Check if there's more work available, just in case it takes | ||
// a while for the Listener to notice connection loss and | ||
// reconnect. | ||
fmt.Println("received no work for 90 seconds, checking for new work") | ||
return | ||
} | ||
} | ||
} | ||
func main() { | ||
var conninfo string = "" | ||
db, err := sql.Open("postgres", conninfo) | ||
if err != nil { | ||
panic(err) | ||
} | ||
reportProblem := func(ev pq.ListenerEventType, err error) { | ||
if err != nil { | ||
fmt.Println(err.Error()) | ||
} | ||
} | ||
listener := pq.NewListener(conninfo, 10 * time.Second, time.Minute, reportProblem) | ||
err = listener.Listen("getwork") | ||
if err != nil { | ||
panic(err) | ||
} | ||
fmt.Println("entering main loop") | ||
for { | ||
// process all available work before waiting for notifications | ||
getWork(db) | ||
waitForNotification(listener) | ||
} | ||
} | ||
*/ | ||
package listen_example |
Oops, something went wrong.