Skip to content

Commit

Permalink
fix: serialize concurrent transactions when running tests with txdb
Browse files Browse the repository at this point in the history
  • Loading branch information
rdmitr committed Jan 2, 2025
1 parent 09ef536 commit 3a4fdf6
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 5 deletions.
14 changes: 14 additions & 0 deletions db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"github.com/getAlby/hub/logger"
)

var SerializeTransactions = false

type Config struct {
URI string
LogQueries bool
Expand Down Expand Up @@ -156,3 +158,15 @@ func Stop(db *gorm.DB) error {
func IsPostgresURI(uri string) bool {
return strings.HasPrefix(uri, "postgresql://")
}

var txSerializer = make(chan struct{}, 1)

func RunTransaction(db *gorm.DB, txFunc func(tx *gorm.DB) error) error {
if SerializeTransactions {
txSerializer <- struct{}{}
defer func() {
<-txSerializer
}()
}
return db.Transaction(txFunc)
}
4 changes: 4 additions & 0 deletions tests/db/test_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ func init() {
uri := GetTestDatabaseURI()
if db.IsPostgresURI(uri) {
txdb.Register(testDriver, "pgx", uri)

// txdb fails when transactions are run concurrently in goroutines
// (concurrent begins/commits/rollback confuse its checkpoints logic).
db.SerializeTransactions = true
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions transactions/transactions_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ func (svc *transactionsService) SendPaymentSync(ctx context.Context, payReq stri
paymentAmount = *amountMsat
}

err = svc.db.Transaction(func(tx *gorm.DB) error {
err = db.RunTransaction(svc.db, func(tx *gorm.DB) error {
var existingSettledTransaction db.Transaction
if tx.Limit(1).Find(&existingSettledTransaction, &db.Transaction{
Type: constants.TRANSACTION_TYPE_OUTGOING,
Expand Down Expand Up @@ -294,7 +294,7 @@ func (svc *transactionsService) SendPaymentSync(ctx context.Context, payReq stri
}

// As the LNClient did not return a timeout error, we assume the payment definitely failed
svc.db.Transaction(func(tx *gorm.DB) error {
db.RunTransaction(svc.db, func(tx *gorm.DB) error {
return svc.markPaymentFailed(tx, &dbTransaction, err.Error())
})

Expand All @@ -303,7 +303,7 @@ func (svc *transactionsService) SendPaymentSync(ctx context.Context, payReq stri

// the payment definitely succeeded
var settledTransaction *db.Transaction
err = svc.db.Transaction(func(tx *gorm.DB) error {
err = db.RunTransaction(svc.db, func(tx *gorm.DB) error {
settledTransaction, err = svc.markTransactionSettled(tx, &dbTransaction, response.Preimage, response.Fee, selfPayment)
return err
})
Expand Down Expand Up @@ -352,7 +352,7 @@ func (svc *transactionsService) SendKeysend(ctx context.Context, amount uint64,

selfPayment := destination == lnClient.GetPubkey()

err = svc.db.Transaction(func(tx *gorm.DB) error {
err = db.RunTransaction(svc.db, func(tx *gorm.DB) error {
err := svc.validateCanPay(tx, appId, amount, "")
if err != nil {
return err
Expand Down Expand Up @@ -464,7 +464,7 @@ func (svc *transactionsService) SendKeysend(ctx context.Context, amount uint64,

// the payment definitely succeeded
var settledTransaction *db.Transaction
err = svc.db.Transaction(func(tx *gorm.DB) error {
err = db.RunTransaction(svc.db, func(tx *gorm.DB) error {
settledTransaction, err = svc.markTransactionSettled(tx, &dbTransaction, preimage, payKeysendResponse.Fee, selfPayment)
return err
})
Expand Down

0 comments on commit 3a4fdf6

Please sign in to comment.