River makes use of drivers to insulate itself from third party packages, enabling future use of other database packages or new major versions. Currently, the two supported drivers are riverdatabasesql
and riverpgxv5
, with riverpgxv5
being the recommended option.
Drivers wrap third party packages
The River Client
takes a generic TTx
type parameter representing the type of the transaction in use for functions like InsertTx
and InsertManyTx
. TTx
is derived from the client's driver, an agnostic interface to a third party package that provides protocol access to Postgres.
Most of the time, the only time code references a database driver is when it's initializing a River client. NewClient
takes a driver as its first parameter, and the driver wraps a database pool:
import "github.com/riverqueue/river"
import "github.com/riverqueue/river/riverdriver/riverpgxv5"
...
dbPool, err := pgxpool.New(ctx, os.Getenv("DATABASE_URL"))
if err != nil {
panic(err)
}
defer dbPool.Close()
riverClient, err := river.NewClient(riverpgxv5.New(dbPool), &river.Config{
...
})
if err != nil {
panic(err)
}
See the InsertAndWork
example for complete code.
Known limitations of riverdatabasesql
The riverdatabasesql
driver has a few known limitations compard to Pgx:
database/sql
doesn't support a way to use Postgres'LISTEN
feature, so workers don't immediately receive signals when jobs are inserted. Instead they enter "poll only mode", which polls periodically for newly available jobs.Some users have tried using the
riverdatabasesql
driver with Pgx through another package like Bun along with its "simple protocol" (pgx.QueryExecModeSimpleProtocol
). This is known to fail, and would require substantial changes toriverdatabasesql
to get working.
In general, riverpgxv5
should be considered River' main supported driver. Pgx is performant, feature complete, production hardened, and well maintained, while Go's database/sql
is broadly considered misdesigned, and too generic to provide access to important Postgres features.