avito-tech/go-transaction-manager

Can trManager manage a transaction if queries to the database are launched in parallel in different goroutines?

Closed this issue · 3 comments

For example:

trManager.Do { 
    g := errGroup{}

    g.Go func1{ updateDB() }
    g.Go func2{ updateDB() }
    g.Go func3{ 
        updateDB()
        time.Sleep(5 seconds)
        return err // will the transaction work correctly?
    }

    return g.Wait()
}

Hello,

Fast answer is yes but there is some restrictions.

  1. Creating nested transaction / savepoints could create problems.
  2. If a database driver, not to be confused with the driver in the trm library, supports concurrency processing.

Also, you can use -race option to check race condition problems.
Could you share more about your use case or more details code?

Thanks for the quick reply!

Sure, here are some details. I connect to different tables in the same database:

import (
	trmsqlx "github.com/avito-tech/go-transaction-manager/sqlx"
	"github.com/jmoiron/sqlx"
)

type FirstRepository struct {
	db            *sqlx.DB
	txGetter  *trmsqlx.CtxGetter
}

type SecondRepository struct {
	db            *sqlx.DB
	txGetter  *trmsqlx.CtxGetter
}

type ThirdRepository struct {
	db            *sqlx.DB
	txGetter  *trmsqlx.CtxGetter
}
//...
trManager := manager.Must(trmsqlx.NewDefaultFactory(postgresDB))
firstRepo = firstRepository.NewFirstRepository(postgresDB, trmsqlx.DefaultCtxGetter)
secondRepo = secondRepository.NewSecondRepository(postgresDB, trmsqlx.DefaultCtxGetter)
thirdRepo = thirdRepository.NewThirdRepository(postgresDB, trmsqlx.DefaultCtxGetter)
job := NewJob(
	trManager,
	firstRepo,
	secondRepo,
        thirdRepo,
)
//...
type Job struct {
	trManager           *manager.Manager
	firstRepo             FirstRepo
	secondRepo       SecondRepo
        thirdRepo            ThirdRepo
}

func (j *Job) Update() {
	g, ctx := errgroup.WithContext(ctx)

        g.Go(func() error {
                return j.firstRepo.Update()
        }
        g.Go(func() error {
                return j.secondRepo.Update()
        }
        g.Go(func() error {
                return j.thirdRepo.Update()
        }

        return g.Wait()
}

I don't see problems but I cannot run and see full code.

However, you don't send ctx in Update and a transaction would not be sent inside repository.