Skip to content

headout/gollback

Repository files navigation

gollback

go reference tests

a simple pgx transaction manager that automatically rolls back on error.
supports timeouts and read-only transactions.

usage

NewTxnProvider returns a transaction manager and a function to get a connection from the pool.

func main() {
    ctx := context.Background()
    
    pool, err := pgxpool.New(ctx, "postgres://user:pass@localhost:5432/db")
    if err != nil {
        panic(err)
    }
    defer pool.Close()
    
    txnManager, getConn := gollback.NewTxnProvider(pool)
}                                                                                                                                                                                                                                                                                                              

replace pgxpool.Pool in your repositories with getConn

type UserRepo struct {
    db getConn
}

func (r *UserRepo) GetByID(ctx context.Contex, id int) (*User, error) {
    return r.db.QueryRow(ctx, "SELECT * FROM users WHERE id = $1", id)
}

your services can now use the transaction manager to string together multiple repository calls into a single transaction.

type Service struct {
    userRepo UserRepo
    postRepo PostRepo
    txnManager gollback.TxnManager
}

func (s *Service) CreatePost(ctx context.Context, userID int, post *Post) error {
    return s.txnManager.RunInTxn(ctx, func(ctx context.Context) error {
        _, err := s.userRepo.GetByID(ctx, UserID)
        if err != nil {
            return err
        }
        _, err = s.postRepo.Create(ctx, post, user.Name)
        if err != nil {
            return err
        }
        return nil
    }
}

  • the transaction is rolled back if the function returns an error
  • the transaction is committed if the function returns nil

advanced

using timeouts

s.txnManager.RunInTxn(ctx, func(ctx context.Context) error {
    return s.userRepo.GetByID(ctx, 123)
}, gollback.WithTimeout(5*time.Second))

Important

the timeout cancels in-progress database operations and prevents commits but does not forcibly terminate your function. If your function has long-running computations between database calls, the transaction will remain open until the function completes. For early exit, check ctx.Done() periodically.

read-only transactions

s.txnManager.RunInTxn(ctx, func(ctx context.Context) error {
    return s.userRepo.GetByID(ctx, 123)
}, gollback.ReadOnly())

the above functional options can be combined.

error handling

the following typed errors are returned by the transaction manager:

  • gollback.TxnBeginError
  • gollback.TxnCommitError
  • gollback.TxnRollbackError
    • the original error is available via .Cause

About

golang pgx transaction manager

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages