Documentation
¶
Overview ¶
Package dbtools contains logic for database transaction, using the retry library.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrEmptyDatabase = errors.New("no database connection is set")
ErrEmptyDatabase is returned when no database connection is set.
Functions ¶
This section is empty.
Types ¶
type ConfigFunc ¶
type ConfigFunc func(*PGX)
A ConfigFunc function sets up a Transaction.
func GracePeriod ¶
func GracePeriod(delay time.Duration) ConfigFunc
GracePeriod sets the context timeout when doing a rollback. This context needs to be different from the context user is giving as the user's context might be cancelled. The default value is 30s.
func Retry ¶
func Retry(attempts int, delay time.Duration) ConfigFunc
Retry sets the retry strategy. If you want to pass a Retry object you can use the WithRetry function instead.
func WithRetry ¶
func WithRetry(r retry.Retry) ConfigFunc
WithRetry sets the retrier. The default retrier tries only once.
type PGX ¶
type PGX struct {
// contains filtered or unexported fields
}
PGX is a concurrent-safe object that can retry a transaction on a pgxpool.Pool connection until it succeeds.
Transaction method will try the provided functions one-by-one until all of them return nil, then commits the transaction. If any of the functions return any error other than a *retry.StopError, it will retry the transaction until the retry count is exhausted. If a running function returns a *retry.StopError, the transaction will be rolled-back and stops retrying. Tryouts will be stopped when the passed contexts are cancelled.
If all attempts return errors, the last error is returned. If a *retry.StopError is returned, transaction is rolled back and the Err inside the *retry.StopError is returned. There will be delays between tries defined by the retry.DelayMethod and Delay duration.
Any panic in functions will be wrapped in an error and will be counted as an error.
func New ¶
func New(conn Pool, conf ...ConfigFunc) (*PGX, error)
New returns an error if conn is nil. It sets the retry attempts to 1 if the value is less than 1. The retry strategy can be set either by providing a retry.Retry method or the individual components. See the ConfigFunc helpers.
func (*PGX) Transaction ¶
Transaction returns an error if the connection is not set, or can't begin the transaction, or the after all retries, at least one of the fns returns an error, or the context is deadlined.
It will wrap the commit/rollback methods if there are any. If in the last try any of the fns panics, it puts the stack trace of the panic in the error and returns.
It stops retrying if any of the errors are wrapped in a *retry.StopError or when the context is cancelled.
Example ¶
tr, err := dbtools.New(&exampleConn{}) if err != nil { panic(err) } err = tr.Transaction(context.Background(), func(pgx.Tx) error { fmt.Println("Running first query.") return nil }, func(pgx.Tx) error { fmt.Println("Running second query.") return nil }) fmt.Printf("Transaction's error: %v", err)
Output: Running first query. Running second query. Transaction's error: <nil>
Example (Panics) ¶
tr, err := dbtools.New(&exampleConn{}, dbtools.Retry(10, 100*time.Millisecond)) if err != nil { panic(err) } calls := 0 err = tr.Transaction(context.Background(), func(pgx.Tx) error { calls++ fmt.Printf("Call #%d.\n", calls) if calls < 5 { panic("We have a panic!") } fmt.Println("All done.") return nil }) fmt.Printf("Transaction's error: %v\n", err) fmt.Printf("Called %d times.\n", calls)
Output: Call #1. Call #2. Call #3. Call #4. Call #5. All done. Transaction's error: <nil> Called 5 times.
Example (Retries) ¶
tr, err := dbtools.New(&exampleConn{}, dbtools.Retry(10, 100*time.Millisecond)) if err != nil { panic(err) } called := false err = tr.Transaction(context.Background(), func(pgx.Tx) error { fmt.Println("Running first query.") return nil }, func(pgx.Tx) error { if !called { called = true fmt.Println("Second query error.") return assert.AnError } fmt.Println("Running second query.") return nil }) fmt.Printf("Transaction's error: %v", err)
Output: Running first query. Second query error. Running first query. Running second query. Transaction's error: <nil>
Example (StopTrying) ¶
// This example shows how to stop trying when we know an error is not // recoverable. tr, err := dbtools.New(&exampleConn{}, dbtools.Retry(10, time.Second), ) if err != nil { panic(err) } err = tr.Transaction(context.Background(), func(pgx.Tx) error { fmt.Println("Running first query.") return nil }, func(pgx.Tx) error { fmt.Println("Running second query.") return &retry.StopError{Err: assert.AnError} }) fmt.Printf("Transaction returns my error: %t", strings.Contains(err.Error(), assert.AnError.Error()))
Output: Running first query. Running second query. Transaction returns my error: true
type Tx ¶
type Tx interface { Commit() error Exec(query string, args ...any) (sql.Result, error) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) Prepare(query string) (*sql.Stmt, error) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) Query(query string, args ...any) (*sql.Rows, error) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) QueryRow(query string, args ...any) *sql.Row QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row Rollback() error Stmt(stmt *sql.Stmt) *sql.Stmt StmtContext(ctx context.Context, stmt *sql.Stmt) *sql.Stmt }
Tx is a transaction began with sql.DB.