-
Notifications
You must be signed in to change notification settings - Fork 14
/
chain.go
124 lines (104 loc) · 2.86 KB
/
chain.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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package manager
import (
"context"
"github.com/avito-tech/go-transaction-manager/trm/v2"
)
// ChainedMW starts transactions in the order given and commit/rollback in reverse order.
//
// WARNING: Rollback of last transactions isn't affected done commits.
// ChainedMW should be only used if the application can tolerate or
// recover from an inconsistent state caused by partially committed transactions.
type ChainedMW struct {
do nextDo
doWithSettings nextDoWithSettings
}
// NewChained creates *ChainedMW or chained trm.Manager.
func NewChained(mm []trm.Manager, _ ...Opt) (*ChainedMW, error) {
if len(mm) == 0 {
return &ChainedMW{
do: nilNextDo,
doWithSettings: nilNextDoWithSettings,
}, nil
}
last := len(mm) - 1
do := newLastDo(mm[last])
doWithSettings := newLastDoWithSettings(mm[last])
for index := last - 1; index >= 0; index-- {
do = newNextDo(mm[index], do)
doWithSettings = newNextDoWithSettings(mm[index], doWithSettings)
}
return &ChainedMW{
do: do,
doWithSettings: doWithSettings,
}, nil
}
// MustChained returns ChainedMW if err is nil and panics otherwise.
func MustChained(mm []trm.Manager, oo ...Opt) *ChainedMW {
s, err := NewChained(mm, oo...)
if err != nil {
panic(err)
}
return s
}
//revive:disable:exported
func (c *ChainedMW) Do(
ctx context.Context,
fn func(ctx context.Context) error,
) error {
return c.do(ctx, fn)
}
type callback func(ctx context.Context) error
type nextDo func(ctx context.Context, fn callback) error
func nilNextDo(ctx context.Context, fn callback) error {
return fn(ctx)
}
func newNextDo(m trm.Manager, n nextDo) nextDo {
return func(ctx context.Context, fn callback) error {
return m.Do(ctx, func(ctx context.Context) error {
return n(ctx, fn)
})
}
}
func newLastDo(m trm.Manager) nextDo {
return func(ctx context.Context, fn callback) error {
return m.Do(ctx, fn)
}
}
// DoWithSettings is an implementation of trm.Manager.
//
// WARNING: trm.CtxKey should not be set in trm.Settings otherwise all trm.Manager would get same trm.Transaction from context.Context.
func (c *ChainedMW) DoWithSettings(
ctx context.Context,
s trm.Settings,
fn func(ctx context.Context) error,
) error {
return c.doWithSettings(ctx, s, fn)
}
type nextDoWithSettings func(context.Context, trm.Settings, callback) error
func nilNextDoWithSettings(
ctx context.Context,
_ trm.Settings,
fn callback,
) error {
return fn(ctx)
}
func newNextDoWithSettings(m trm.Manager, n nextDoWithSettings) nextDoWithSettings {
return func(
ctx context.Context,
s trm.Settings,
fn callback,
) error {
return m.DoWithSettings(ctx, s, func(ctx context.Context) error {
return n(ctx, s, fn)
})
}
}
func newLastDoWithSettings(m trm.Manager) nextDoWithSettings {
return func(
ctx context.Context,
s trm.Settings,
fn callback,
) error {
return m.DoWithSettings(ctx, s, fn)
}
}