techschool / simplebank

Backend master class: build a simple bank service in Go
MIT License
5.33k stars 961 forks source link

Getting : BUG: slow write timer already active #119

Open bilal-psychplus opened 6 months ago

bilal-psychplus commented 6 months ago

This my storage.go file

package db

import (
    "context"
    "fmt"

    "github.com/jackc/pgx/v5"
    "github.com/jackc/pgx/v5/pgtype"
)

//Store provides all functions to execute db queries and transactions
type Store struct {
    *Queries
    db *pgx.Conn
}

type TransferTxParams struct {
    FromAccountID int64                     `json:"from_account_id"`
    ToAccountID     int64                   `json:"to_account_id"`
    Amount              pgtype.Numeric  `json:"amount"`
}

type TransferTxResult struct {
    Transfer Transfer `json:"transfer"`
    FromAccount Account `json:"from_account"`
    ToAccount Account `json:"to_account"`
    FromEntry Entry `json:"from_entry"`
    ToEntry Entry `json:"to_entry"`
}

func NewStore(db *pgx.Conn) *Store {
        return &Store{
            db: db,
            Queries: New(db),
        }
}
//executeTranscation executres a function within a database transaction
func (store *Store) executeTransaction(ctx context.Context, fn func(*Queries) error) error {
    options := pgx.TxOptions {
        IsoLevel: pgx.TxIsoLevel(pgx.Deferrable),
        AccessMode: pgx.ReadWrite,
    }
    transaction, err := store.db.BeginTx(ctx, options)
    if err != nil {
        return err
    }
    query := New(transaction)
    err = fn(query)
    if err != nil {
        if rollbackError := transaction.Rollback(ctx); rollbackError != nil {
            return fmt.Errorf("transaction error: %v, rollback error: %v", err, rollbackError)
        }
        return err
    }
    return transaction.Commit(ctx)
}

func (store *Store) TransferTx(ctx context.Context, arg TransferTxParams) (TransferTxResult, error) {
    var result TransferTxResult
    err := store.executeTransaction(ctx, func(query *Queries) error {
        var err error

        transfer := CreateTransferParams(TransferTxParams {
            FromAccountID:  arg.FromAccountID,
            ToAccountID:        arg.ToAccountID,
            Amount:                 arg.Amount,
        })

        result.Transfer, err = query.CreateTransfer(ctx, transfer)
        if err != nil {
            return err
        }

        // result.FromEntry, err = query.CreateEntry(ctx, CreateEntryParams {
        //  AccountID: arg.FromAccountID,
        //  Amount: -arg.Amount.Int.Int64(),
        // })
        // if err != nil {
        //  return err
        // }

        // result.ToEntry, err = query.CreateEntry(ctx, CreateEntryParams {
        //  AccountID: arg.ToAccountID,
        //  Amount: arg.Amount.Int.Int64(),
        // })
        // if err != nil {
        //  return err
        // }

        // // TODO: update account's balance
        // account1, err := query.GetAccountForUpdate(ctx, arg.FromAccountID);
        // if err != nil {
        //  return err
        // }

        // result.FromAccount, err = query.UpdateAccount(ctx, UpdateAccountParams {
        //  ID: arg.FromAccountID,
        //  Balance: util.FromIntToPgNumeric(account1.Balance.Int.Int64() - arg.Amount.Int.Int64()),
        // })
        // if err != nil {
        //  return err
        // }

        // account2, err := query.GetAccountForUpdate(ctx, arg.ToAccountID);
        // if err != nil {
        //  return err
        // }

        // result.ToAccount, err = query.UpdateAccount(ctx, UpdateAccountParams {
        //  ID: arg.ToAccountID,
        //  Balance: util.FromIntToPgNumeric(account2.Balance.Int.Int64() + arg.Amount.Int.Int64()),
        // })

        // if err != nil {
        //  return err
        // }

        return nil
    })
    return result, err
}

And i am getting the following errors

>> before: 579 832
panic: BUG: slow write timer already active

goroutine 37 [running]:
github.com/jackc/pgx/v5/pgconn.(*PgConn).enterPotentialWriteReadDeadlock(...)
        /Users/bilalashraf/go/pkg/mod/github.com/jackc/pgx/v5@v5.5.5/pgconn/pgconn.go:1833
github.com/jackc/pgx/v5/pgconn.(*PgConn).flushWithPotentialWriteReadDeadlock(0x14000103680)
        /Users/bilalashraf/go/pkg/mod/github.com/jackc/pgx/v5@v5.5.5/pgconn/pgconn.go:1852 +0xb4
github.com/jackc/pgx/v5/pgconn.(*PgConn).Close(0x14000103680, {0x1009768a0?, 0x140000a8000})
        /Users/bilalashraf/go/pkg/mod/github.com/jackc/pgx/v5@v5.5.5/pgconn/pgconn.go:640 +0x160
github.com/jackc/pgx/v5.(*Conn).die(0x14000151c20, {0x1009767f8?, 0x100c9ef40?})
        /Users/bilalashraf/go/pkg/mod/github.com/jackc/pgx/v5@v5.5.5/conn.go:412 +0x74
github.com/jackc/pgx/v5.(*Conn).BeginTx(0x14000151c20, {0x1009767f8, 0x100c9ef40}, {{0x1007eca5c, 0xa}, {0x1007eca66, 0xa}, {0x0, 0x0}, {0x0, ...}})
        /Users/bilalashraf/go/pkg/mod/github.com/jackc/pgx/v5@v5.5.5/tx.go:104 +0x120
github.com/billalaashraf/simplebank/db/sqlc.(*Store).executeTransaction(0x0?, {0x1009767f8, 0x100c9ef40}, 0x140000b1960)
        /Users/bilalashraf/Work/Backend/simplebank/db/sqlc/storage.go:43 +0x80
github.com/billalaashraf/simplebank/db/sqlc.(*Store).TransferTx(_, {_, _}, {_, _, {_, _, _, _, _}})
        /Users/bilalashraf/Work/Backend/simplebank/db/sqlc/storage.go:60 +0xc8
github.com/billalaashraf/simplebank/db/sqlc.TestTransferTx.func1()
        /Users/bilalashraf/Work/Backend/simplebank/db/sqlc/storage_test.go:29 +0xa0
created by github.com/billalaashraf/simplebank/db/sqlc.TestTransferTx in goroutine 35
        /Users/bilalashraf/Work/Backend/simplebank/db/sqlc/storage_test.go:28 +0x2e0
FAIL    github.com/billalaashraf/simplebank/db/sqlc     0.698s
FAIL

What am i missing here.

SaeedSkf commented 2 months ago

you should change pgx.Conn to pgxpool.Pool, like below:


package db

import (
    "context"
    "log"
    "os"
    "testing"

    "github.com/jackc/pgx/v5/pgxpool"
    _ "github.com/lib/pq"
)

const (
    dbSource = "postgresql://root:secret@localhost:5432/simple_bank?sslmode=disable"
)

var testQueries *Queries
var testDB *pgxpool.Pool

func TestMain(m *testing.M) {
    ctx := context.Background()
    var err error

    testDB, err = pgxpool.New(ctx, dbSource)
    if err != nil {
        log.Fatal("Can not connect to the db: ", err)
    }
    defer testDB.Close()

    testQueries = New(testDB)

    os.Exit(m.Run())
}