Skip to content

Add a transaction runner for a plain database handle #80

Closed

Description

@SirLouen

What

Add a function-style transaction runner to dbkit for a plain *sql.DB, for example:

func InTx(ctx context.Context, db *sql.DB, body func(*sql.Tx) error) error

It begins a transaction, runs body, commits when body succeeds and rolls back otherwise, also when body panics or the commit fails.

Why

Two stores already carry their own copy of the same few lines:

  • gouncer's authkit/sqlite store (inTx in store.go)
  • Gophenberg's SQLite site settings store (internal/sqlite/tx.go)

Each copy has to get the deferred rollback right. If one forgets it, a failed write on SQLite keeps the file's write lock until its context ends, and every later writer then waits and fails as busy. One tested runner in dbkit removes that risk for every caller. Laravel (DB::transaction), Rails (ActiveRecord::Base.transaction) and Django (transaction.atomic) all keep this helper in the framework for the same reason.

dbkit.Share already has Begin. The runner could sit beside it, or take the share as well as a plain handle.

Activity

  1. KeuqS commented on Oct 14, 2026

    @KeuqS
    Contributor

    I can take this. I will add a small dbkit.InTx helper for plain *sql.DB handles, with tests covering commit, rollback on body error, and panic cleanup.

  2. KeuqS commented on Oct 14, 2026

    @KeuqS
    Contributor

    Implementation is ready in PR #82: #82. It adds dbkit.InTx with commit, rollback, and panic-cleanup tests.

  3. SirLouen commented on Oct 14, 2026

    @SirLouen
    MemberAuthor

    One more thing the runner should do: report a rollback that fails. Both copies today drop it with defer func() { _ = tx.Rollback() }(). After a successful commit, Rollback returns sql.ErrTxDone, which is expected. After a failed body, any other rollback error should be joined to the body's error, for example with errors.Join, so the caller sees both.

    The product cannot test this today, because sqlitetest.Faults can fail a statement or a commit but not a rollback. A FailNextRollback beside FailNextCommit would let dbkit pin it.

  4. self-assigned this
    on Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Fields

Priority

None yet

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions