Sobes.tech
Senior

Já trabalhou com transações ao nível de processos de negócio — SELECT FOR UPDATE, rollback em caso de falha na API externa?

sobes.tech IA

Resposta da IA

Sim, trabalhei com transações ao nível dos processos de negócio em Go. Usei SELECT FOR UPDATE para bloquear linhas na base de dados, evitando condições de corrida em operações paralelas. Por exemplo, ao reservar um produto numa encomenda, primeiro fazia uma seleção com bloqueio, depois atualizava a quantidade, e só após uma interação bem-sucedida com a API externa, confirmava a transação.

Se a API externa falhasse, chamava rollback da transação para não guardar alterações na base de dados e não deixar o sistema num estado inconsistente.

Exemplo usando database/sql e PostgreSQL:

ctx := context.Background()
tx, err := db.BeginTx(ctx, nil)
if err != nil {
    return err
}

// Bloquear a linha
row := tx.QueryRowContext(ctx, "SELECT quantity FROM products WHERE id=$1 FOR UPDATE", productID)
var quantity int
if err := row.Scan(&quantity); err != nil {
    tx.Rollback()
    return err
}

if quantity < needed {
    tx.Rollback()
    return errors.New("stock insuficiente")
}

// Chamada à API externa
if err := callExternalAPI(); err != nil {
    tx.Rollback()
    return err
}

// Atualizar quantidade
_, err = tx.ExecContext(ctx, "UPDATE products SET quantity = quantity - $1 WHERE id = $2", needed, productID)
if err != nil {
    tx.Rollback()
    return err
}

return tx.Commit()

Esta abordagem garante a atomicidade da operação de negócio e a coerência dos dados.