Skip to content

Commit 334154e

Browse files
authored
Fix goroutine leak v2 (#104)
1 parent f4be550 commit 334154e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1339
-648
lines changed

.github/workflows/main.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ env:
1111
OS_TARGET: ubuntu-latest
1212
jobs:
1313
tests-units:
14+
needs: [lint]
1415
permissions:
1516
pull-requests: write
1617
strategy:
@@ -52,6 +53,7 @@ jobs:
5253
run: make test
5354

5455
tests-integration:
56+
needs: [tests-units]
5557
permissions:
5658
pull-requests: write
5759
services:
@@ -145,7 +147,7 @@ jobs:
145147
with:
146148
go-version: ${{ env.GO_TARGET_VERSION }}
147149
- name: golangci-lint
148-
uses: golangci/golangci-lint-action@v3
150+
uses: golangci/golangci-lint-action@v4
149151
with:
150152
args: --timeout=3m -v
151153
working-directory: ${{ matrix.modules }}

.golangci.yml

+4
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ linters:
6363
- whitespace
6464
- wsl # https://github.com/bombsimon/wsl/blob/master/doc/rules.md
6565

66+
linters-settings:
67+
wsl:
68+
allow-assign-and-anything: true
69+
6670
issues:
6771
exclude-use-default: false
6872
exclude:

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
## [2.0.0-rc-8] - 2024-01-04
9+
10+
### Fixed
11+
12+
- gouroutine leak.
13+
14+
## [2.0.0-rc-7] - 2024-01-04
15+
16+
### Changes
17+
18+
- Transferred drivers in separated modules.
19+
820
## [1.4.0] - 2023-09-01
921

1022
### Added

drivers/goredis8/factory.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import (
55

66
"github.com/go-redis/redis/v8"
77

8-
trm "github.com/avito-tech/go-transaction-manager/trm/v2"
8+
"github.com/avito-tech/go-transaction-manager/trm/v2"
99
)
1010

1111
// NewDefaultFactory creates default trm.Transaction(redis.UniversalClient).
1212
func NewDefaultFactory(db redis.UniversalClient) trm.TrFactory {
1313
return func(ctx context.Context, trms trm.Settings) (context.Context, trm.Transaction, error) {
14-
s, _ := trms.(Settings)
14+
s, ok := trms.(*Settings)
15+
if !ok {
16+
s, _ = NewSettings(trms)
17+
}
1518

1619
return NewTransaction(ctx, db, s)
1720
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//go:build go1.20
2+
// +build go1.20
3+
4+
package goredis8
5+
6+
import (
7+
"testing"
8+
9+
"go.uber.org/goleak"
10+
)
11+
12+
func TestMain(m *testing.M) {
13+
// https://github.com/redis/go-redis/issues/1029
14+
goleak.VerifyTestMain(m, goleak.IgnoreAnyFunction("github.com/go-redis/redis/v8/internal/pool.(*ConnPool).reaper"))
15+
}

drivers/goredis8/option.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import "github.com/go-redis/redis/v8"
55
// WithMulti sets up sql.TxOptions for the Settings.
66
func WithMulti(isMulti bool) Opt {
77
return func(s *Settings) error {
8-
*s = s.setIsMulti(&isMulti)
8+
s.setIsMulti(&isMulti)
99

1010
return nil
1111
}
@@ -14,7 +14,7 @@ func WithMulti(isMulti bool) Opt {
1414
// WithWatchKeys sets WATCH keys in Transaction.
1515
func WithWatchKeys(keys ...string) Opt {
1616
return func(s *Settings) error {
17-
*s = s.setWatchKeys(keys)
17+
s.setWatchKeys(keys)
1818

1919
return nil
2020
}
@@ -23,7 +23,7 @@ func WithWatchKeys(keys ...string) Opt {
2323
// WithTxDecorator sets TxDecorator to change behavior of Transaction.
2424
func WithTxDecorator(in TxDecorator) Opt {
2525
return func(s *Settings) error {
26-
*s = s.setTxDecorator(in)
26+
s.setTxDecorator(in)
2727

2828
return nil
2929
}
@@ -33,7 +33,7 @@ func WithTxDecorator(in TxDecorator) Opt {
3333
// WARNING: Responses don't clean automatically, use WithRet only with DoWithSettings of trm.Manager.
3434
func WithRet(in *[]redis.Cmder) Opt {
3535
return func(s *Settings) error {
36-
*s = s.SetReturn(in)
36+
s.SetReturn(in)
3737

3838
return nil
3939
}

drivers/goredis8/settings.go

+54-24
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package goredis8
22

33
import (
4+
"sync"
5+
46
"github.com/go-redis/redis/v8"
57

6-
trm "github.com/avito-tech/go-transaction-manager/trm/v2"
8+
"github.com/avito-tech/go-transaction-manager/trm/v2"
79
)
810

911
const (
@@ -20,30 +22,33 @@ type Settings struct {
2022
isMulti *bool
2123
watchKeys []string
2224
txDecorator []TxDecorator
23-
ret *[]redis.Cmder
25+
26+
ret *[]redis.Cmder
27+
muRet sync.RWMutex
2428
}
2529

2630
// NewSettings creates Settings.
27-
func NewSettings(trms trm.Settings, oo ...Opt) (Settings, error) {
31+
func NewSettings(trms trm.Settings, oo ...Opt) (*Settings, error) {
2832
s := &Settings{
2933
Settings: trms,
3034
isMulti: nil,
3135
watchKeys: nil,
3236
txDecorator: nil,
3337
ret: nil,
38+
muRet: sync.RWMutex{},
3439
}
3540

3641
for _, o := range oo {
3742
if err := o(s); err != nil {
38-
return Settings{}, err
43+
return nil, err
3944
}
4045
}
4146

42-
return *s, nil
47+
return s, nil
4348
}
4449

4550
// MustSettings returns Settings if err is nil and panics otherwise.
46-
func MustSettings(trms trm.Settings, oo ...Opt) Settings {
51+
func MustSettings(trms trm.Settings, oo ...Opt) *Settings {
4752
s, err := NewSettings(trms, oo...)
4853
if err != nil {
4954
panic(err)
@@ -53,8 +58,8 @@ func MustSettings(trms trm.Settings, oo ...Opt) Settings {
5358
}
5459

5560
// EnrichBy fills nil properties from external Settings.
56-
func (s Settings) EnrichBy(in trm.Settings) trm.Settings {
57-
external, ok := in.(Settings)
61+
func (s *Settings) EnrichBy(in trm.Settings) trm.Settings {
62+
external, ok := in.(*Settings)
5863
if ok {
5964
if s.IsMultiOrNil() == nil {
6065
s = s.SetIsMulti(external.IsMultiOrNil())
@@ -68,8 +73,8 @@ func (s Settings) EnrichBy(in trm.Settings) trm.Settings {
6873
s = s.SetTxDecorators(external.TxDecorators()...)
6974
}
7075

71-
if s.Return() == nil {
72-
s = s.SetReturn(external.Return())
76+
if s.ReturnPtr() == nil {
77+
s = s.SetReturn(external.ReturnPtr())
7378
}
7479
}
7580

@@ -79,7 +84,7 @@ func (s Settings) EnrichBy(in trm.Settings) trm.Settings {
7984
}
8085

8186
// IsMulti - true uses redis MULTI cmd.
82-
func (s Settings) IsMulti() bool {
87+
func (s *Settings) IsMulti() bool {
8388
if s.isMulti == nil {
8489
return DefaultMulti
8590
}
@@ -88,64 +93,89 @@ func (s Settings) IsMulti() bool {
8893
}
8994

9095
// IsMultiOrNil returns IsMulti or nil.
91-
func (s Settings) IsMultiOrNil() *bool {
96+
func (s *Settings) IsMultiOrNil() *bool {
9297
return s.isMulti
9398
}
9499

95100
// SetIsMulti set using or not Multi for transaction, see https://redis.uptrace.dev/guide/go-redis-pipelines.html#transactions.
96-
func (s Settings) SetIsMulti(in *bool) Settings {
101+
func (s *Settings) SetIsMulti(in *bool) *Settings {
97102
return s.setIsMulti(in)
98103
}
99104

100-
func (s Settings) setIsMulti(in *bool) Settings {
105+
func (s *Settings) setIsMulti(in *bool) *Settings {
101106
s.isMulti = in
102107

103108
return s
104109
}
105110

106111
// WatchKeys returns keys for watching.
107-
func (s Settings) WatchKeys() []string {
112+
func (s *Settings) WatchKeys() []string {
108113
return s.watchKeys
109114
}
110115

111116
// SetWatchKeys sets keys for watching, see https://redis.uptrace.dev/guide/go-redis-pipelines.html#watch.
112-
func (s Settings) SetWatchKeys(in []string) Settings {
117+
func (s *Settings) SetWatchKeys(in []string) *Settings {
113118
return s.setWatchKeys(in)
114119
}
115120

116-
func (s Settings) setWatchKeys(in []string) Settings {
121+
func (s *Settings) setWatchKeys(in []string) *Settings {
117122
s.watchKeys = in
118123

119124
return s
120125
}
121126

122127
// TxDecorators returns TxDecorator decorators.
123-
func (s Settings) TxDecorators() []TxDecorator {
128+
func (s *Settings) TxDecorators() []TxDecorator {
124129
return s.txDecorator
125130
}
126131

127132
// SetTxDecorators sets TxDecorator decorators.
128-
func (s Settings) SetTxDecorators(in ...TxDecorator) Settings {
133+
func (s *Settings) SetTxDecorators(in ...TxDecorator) *Settings {
129134
return s.setTxDecorator(in...)
130135
}
131136

132-
func (s Settings) setTxDecorator(in ...TxDecorator) Settings {
137+
func (s *Settings) setTxDecorator(in ...TxDecorator) *Settings {
133138
s.txDecorator = in
134139

135140
return s
136141
}
137142

138-
// Return returns []redis.Cmder from Transaction.
139-
func (s Settings) Return() *[]redis.Cmder {
143+
// ReturnPtr returns link to save []redis.Cmder from Transaction.
144+
func (s *Settings) ReturnPtr() *[]redis.Cmder {
145+
s.muRet.RLock()
146+
defer s.muRet.RUnlock()
147+
140148
return s.ret
141149
}
142150

151+
// Return returns []redis.Cmder from Transaction.
152+
func (s *Settings) Return() []redis.Cmder {
153+
res := s.ReturnPtr()
154+
if res != nil {
155+
return *s.ReturnPtr()
156+
}
157+
158+
return nil
159+
}
160+
161+
// AppendReturn append []redis.Cmder from Transaction.
162+
func (s *Settings) AppendReturn(cmds ...redis.Cmder) {
163+
if s.ReturnPtr() == nil {
164+
return
165+
}
166+
167+
s.muRet.Lock()
168+
defer s.muRet.Unlock()
169+
170+
*s.ret = append(*s.ret, cmds...)
171+
}
172+
143173
// SetReturn sets link to save []redis.Cmder from Transaction.
144-
func (s Settings) SetReturn(in *[]redis.Cmder) Settings {
174+
func (s *Settings) SetReturn(in *[]redis.Cmder) *Settings {
145175
return s.setReturn(in)
146176
}
147177

148-
func (s Settings) setReturn(in *[]redis.Cmder) Settings {
178+
func (s *Settings) setReturn(in *[]redis.Cmder) *Settings {
149179
s.ret = in
150180

151181
return s

0 commit comments

Comments
 (0)