-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtxn_exec.go
57 lines (54 loc) · 1.36 KB
/
txn_exec.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package txn
import (
"context"
"fmt"
"runtime/debug"
)
// DoFunc defines the function type for transaction execution.
type DoFunc[O any, B any, D Doer[O, B]] func(ctx context.Context, do D) error
// Execute executes a transaction with the given Doer and function.
func Execute[
O any,
B any,
D Doer[O, B],
F DoFunc[O, B, D],
](ctx context.Context, db B, doer D, fn F) (err error) {
select {
case <-ctx.Done():
return fmt.Errorf("%w [txn context done]", ctx.Err())
default:
var txn Txn
if txn, err = doer.BeginTxn(ctx, db); err != nil {
return fmt.Errorf("%w [txn begin]", err)
}
defer func() {
if p := recover(); p != nil {
if doer.Rethrow() {
panic(p)
}
err = fmt.Errorf("%v --- debug.Stack --- %s", p, debug.Stack())
if x := txn.Rollback(ctx); x != nil {
err = fmt.Errorf("%w [txn recover] %w [rollback]", err, x)
} else {
err = fmt.Errorf("%w [txn recover]", err)
}
}
}()
if err = fn(ctx, doer); err != nil {
if x := txn.Rollback(ctx); x != nil {
return fmt.Errorf("%w [txn do] %w [rollback]", err, x)
} else {
return fmt.Errorf("%w [txn do]", err)
}
}
if err = txn.Commit(ctx); err != nil {
if x := txn.Rollback(ctx); x != nil {
return fmt.Errorf("%w [txn commit] %w [rollback]", err, x)
} else {
return fmt.Errorf("%w [txn commit]", err)
}
} else {
return nil
}
}
}