Skip to content

Commit 64242cd

Browse files
committed
Updates README
1 parent fd28a8b commit 64242cd

File tree

1 file changed

+100
-49
lines changed

1 file changed

+100
-49
lines changed

README.md

+100-49
Original file line numberDiff line numberDiff line change
@@ -26,65 +26,116 @@ import (
2626
"context"
2727
"database/sql"
2828

29-
twophase "github.com/gosom/go-sql-2pc"
29+
"github.com/gosom/gosql2pc"
30+
twophase "github.com/gosom/gosql2pc"
3031
_ "github.com/jackc/pgx/stdlib"
3132
)
3233

3334
func main() {
34-
// Connect to the database
35-
db1, err := sql.Open("pgx", "postgres://user:password@host1/mydb1?sslmode=disable")
36-
if err != nil {
37-
panic(err)
38-
}
39-
defer db1.Close()
40-
db2, err := sql.Open("pgx", "postgres://user:password@host2/mydb2?sslmode=disable")
41-
if err != nil {
42-
panic(err)
43-
}
44-
defer db2.Close()
45-
46-
// Create some tables for testing
47-
// One table for users in db1
48-
_, err = db1.Exec("CREATE TABLE IF NOT EXISTS users (id uuid not null primary key, name text)")
49-
if err != nil {
50-
return nil, nil, err
51-
}
52-
// One table for orders in db2
53-
_, err = db2.Exec(`CREATE TABLE IF NOT EXISTS orders(
35+
// Connect to the database
36+
db1, err := sql.Open("pgx", "postgres://user1:secret@localhost:5432/user1?sslmode=disable")
37+
if err != nil {
38+
panic(err)
39+
}
40+
defer db1.Close()
41+
db2, err := sql.Open("pgx", "postgres://user2:secret@localhost:5433/user2?sslmode=disable")
42+
if err != nil {
43+
panic(err)
44+
}
45+
defer db2.Close()
46+
47+
// Create some tables for testing
48+
// One table for users in db1
49+
_, err = db1.Exec("CREATE TABLE IF NOT EXISTS users (id uuid not null primary key, name text)")
50+
if err != nil {
51+
panic(err)
52+
}
53+
// One table for orders in db2
54+
_, err = db2.Exec(`CREATE TABLE IF NOT EXISTS orders(
5455
id uuid not null primary key,
5556
user_id uuid not null,
5657
amount int not null)`)
57-
if err != nil {
58-
return nil, nil, err
59-
}
60-
61-
userID := "47f89b20-cb3a-11ed-8475-aba23b81b15d"
62-
name := "John Doe"
63-
amount := 10
64-
65-
// Create the participants for the 2 phase commit
66-
p1 := twophase.NewParticipant(db1, func(ctx context.Context, tx *sql.Tx) error {
67-
_, err := tx.ExecContext(ctx, "INSERT INTO users (id, name) VALUES ($1, $2)", userID, name)
68-
return err
69-
})
70-
71-
p2 := twophase.NewParticipant(orderdb, func(ctx context.Context, tx *sql.Tx) error {
72-
_, err := tx.ExecContext(ctx, "INSERT INTO orders (id, user_id, amount) VALUES ($1, $2, $3)", orderID, userID, amount)
73-
return err
74-
})
75-
76-
// setup the parameters for the transaction
77-
params := twophase.Params{
78-
Participants: []gosql2pc.Participant{p1, p2},
79-
}
80-
81-
// run the transaction
82-
if err := twophase.Do(context.Background(), params); err != nil {
83-
panic(err)
84-
}
58+
if err != nil {
59+
panic(err)
60+
}
61+
62+
userID := "47f89b20-cb3a-11ed-8475-aba23b81b15d"
63+
name := "John Doe"
64+
orderID := "a444eeaa-cb3b-11ed-a5c2-3b46183795fa"
65+
amount := 10
66+
67+
// Create the participants for the 2 phase commit
68+
p1 := twophase.NewParticipant(db1, func(ctx context.Context, tx *sql.Tx) error {
69+
_, err := tx.ExecContext(ctx, "INSERT INTO users (id, name) VALUES ($1, $2)", userID, name)
70+
return err
71+
})
72+
73+
p2 := twophase.NewParticipant(db2, func(ctx context.Context, tx *sql.Tx) error {
74+
_, err := tx.ExecContext(ctx, "INSERT INTO orders (id, user_id, amount) VALUES ($1, $2, $3)", orderID, userID, amount)
75+
return err
76+
})
77+
78+
// setup the parameters for the transaction
79+
params := twophase.Params{
80+
Participants: []gosql2pc.Participant{p1, p2},
81+
}
82+
83+
// run the transaction
84+
if err := twophase.Do(context.Background(), params); err != nil {
85+
panic(err)
86+
}
8587
}
8688
```
8789

90+
### Examples
91+
92+
In the `examples` directory there is an executable with some examples.
93+
94+
```
95+
cd examples
96+
docker-compose up -d
97+
```
98+
99+
then you can run the 3 examples. Please read the source code and it's comments.
100+
101+
```
102+
go run main.go -cmd=basic
103+
go run main.go -cmd=concurrency1
104+
go run main.go -cmd=concurrency2
105+
```
106+
107+
## Caution
108+
109+
PostgreSQL has by default disabled the `prepared_transactions`. There is a good reason for that.
110+
You may even locked out of the database of permanently lock a table.
111+
112+
You need a mechanism that monitors that monitors any orphaned prepared transactions and takes action.
113+
114+
Please read the [documentation](https://www.postgresql.org/docs/current/sql-prepare-transaction.html)
115+
and [this blog post](https://www.cybertec-postgresql.com/en/prepared-transactions/)
116+
and [this blog post](https://www.highgo.ca/2020/01/28/understanding-prepared-transactions-and-handling-the-orphans/).
117+
118+
Don't be afraid but you should know with what you are dealing with.
119+
120+
In order to enable prepared transactions set in `postgresql.conf`
121+
`max_prepared_transactions` to something larger that zero. Better to set it to the number of `max_connections`
122+
123+
Alternatevely, you can set it when you start the postgreSQL server by using the `-c` flag.
124+
(see the docker-compose.yaml in the `examples` folder).
125+
126+
127+
The library gives you some level of consistency BUT when the process that coordinates the distributed transactions crashes you may leave orphan prepared transactions or having data inconsistency since only some of the
128+
participants may have finished the commits.
129+
130+
Additionally, if one participant manages to commit and the others don't (because of a disk failure for example) then again you may have data incosistency. I recommend to have some monitoring for these cases.
131+
132+
133+
Consider if you actually need to phase commit or you can use maybe Sagas. Both patterns are useful, but
134+
I believe that Sagas are more generic since in order to use the 2 Phase Commit Protocol all the
135+
platforms need to implement the protocol. In any case distributed transactions are not trivial and you
136+
should be careful.
137+
138+
88139
## Contributing
89140
Contributions to go-sql-2pc are always welcome. If you find a bug or want to suggest a new feature, please open an issue or submit a pull request.
90141

0 commit comments

Comments
 (0)