Skip to content

Commit 480123d

Browse files
committed
Fixing connection string super bug and improving structure
1 parent 71e4a76 commit 480123d

19 files changed

+184
-155
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type testDocStruct struct {
3737

3838
func main() {
3939
const (
40+
appName = "my app"
4041
connTimeoutSeconds = 10 // Time to wait for the first connection
4142
execTimeoutSeconds = 10 // Time to wait for execution
4243
reconnTimeoutSeconds = 10 // Time between reconnection attempts
@@ -53,7 +54,7 @@ func main() {
5354

5455
log.Println("Connecting db...")
5556

56-
if _m, err := mongohelper.New(testConnectionString, mongohelper.OptionsNew(connTimeoutSeconds, execTimeoutSeconds, reconnTimeoutSeconds, reconnAttemptsLimit, reconnAttemptsLimitMinutes, insistOnFailure, logDebugMessages)); err != nil {
57+
if _m, err := mongohelper.New(mongohelper.OptionsNew(appName,testConnectionString,connTimeoutSeconds, execTimeoutSeconds, reconnTimeoutSeconds, reconnAttemptsLimit, reconnAttemptsLimitMinutes, insistOnFailure, logDebugMessages)); err != nil {
5758
log.Fatal(err)
5859
} else {
5960
mdb = *_m

collection.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package mongohelper
2+
3+
import "go.mongodb.org/mongo-driver/mongo"
4+
5+
// Collection returns a collection from the target database
6+
func (l Link) Collection(database, collection string) (*mongo.Collection, error) {
7+
if err := l.linkCheck("link.Collection"); err != nil {
8+
return nil, err
9+
}
10+
11+
return l.client.Database(database).Collection(collection), nil
12+
}

connect.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package mongohelper
2+
3+
import (
4+
"context"
5+
"go.mongodb.org/mongo-driver/mongo"
6+
"go.mongodb.org/mongo-driver/mongo/options"
7+
"go.mongodb.org/mongo-driver/mongo/readpref"
8+
"time"
9+
)
10+
11+
func (l Link) ping() error {
12+
ctx, cancel := context.WithTimeout(context.Background(), l.connTimeout())
13+
14+
defer cancel()
15+
16+
return l.client.Ping(ctx, readpref.Primary())
17+
}
18+
19+
// connect tries to conect database using the given options
20+
func (l *Link) connect() error {
21+
var ctx context.Context
22+
23+
// Context with timeout can't be used in loops, because they expire before the loop complete its job
24+
if l.insistOnFail() {
25+
ctx = context.Background()
26+
} else {
27+
timeout := time.Duration(l.options.connTimeoutSeconds) * time.Second
28+
29+
_ctx, cancel := context.WithTimeout(context.Background(), timeout)
30+
31+
ctx = _ctx
32+
33+
defer cancel()
34+
}
35+
36+
for {
37+
var err error
38+
39+
opts := options.Client().ApplyURI(l.connectionString())
40+
opts.SetConnectTimeout(l.connTimeout())
41+
opts.SetMaxConnIdleTime(8 * time.Hour)
42+
opts.SetSocketTimeout(l.execTimeout())
43+
opts.SetMinPoolSize(10)
44+
opts.SetAppName(l.appName())
45+
46+
l.client, err = mongo.Connect(ctx, opts)
47+
48+
if err != nil {
49+
l.log("mongo.Connect", err.Error())
50+
}
51+
52+
err = l.client.Ping(context.Background(), readpref.Primary())
53+
54+
if err != nil {
55+
l.log("mongo.Ping", err.Error())
56+
} else {
57+
l.notifyConnection()
58+
59+
return nil
60+
}
61+
62+
if l.insistOnFail() {
63+
if l.canInsist() {
64+
l.wait()
65+
l.increment()
66+
continue
67+
}
68+
}
69+
70+
return err
71+
}
72+
}

countdocs.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package mongohelper
33
import (
44
"context"
55
"errors"
6-
"fmt"
76
"go.mongodb.org/mongo-driver/mongo"
87
"go.mongodb.org/mongo-driver/mongo/options"
98
)
@@ -15,8 +14,8 @@ import (
1514
// cannot be nil. An empty document (e.g. bson.D{}) should be used to count all documents in the collection. This will
1615
// result in a full collection scan.
1716
func (l *Link) CountDocs(database, collection string, filter interface{}) (int64, error) {
18-
if l.client == nil {
19-
return 0, fmt.Errorf("mongohelper is not connected")
17+
if err := l.linkCheck("link.CountDocs"); err != nil {
18+
return 0, err
2019
}
2120

2221
ctx, cancel := context.WithTimeout(context.Background(), l.execTimeout())

deletemany.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@ package mongohelper
33
import (
44
"context"
55
"errors"
6-
"fmt"
76
"go.mongodb.org/mongo-driver/mongo"
87
"go.mongodb.org/mongo-driver/mongo/options"
98
)
109

1110
// DeleteMany wraps the mongo.Database.Collection.DeleteMany() method
1211
// It returns the number of affected records and an error
1312
func (l *Link) DeleteMany(database, collection string, filter interface{}) (int64, error) {
14-
if l.client == nil {
15-
return 0, fmt.Errorf("mongohelper is not connected")
13+
if err := l.linkCheck("link.DeleteMany"); err != nil {
14+
return 0, err
1615
}
1716

1817
ctx, cancel := context.WithTimeout(context.Background(), l.execTimeout())

deleteone.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@ package mongohelper
33
import (
44
"context"
55
"errors"
6-
"fmt"
76
"go.mongodb.org/mongo-driver/mongo"
87
"go.mongodb.org/mongo-driver/mongo/options"
98
)
109

1110
// DeleteOne wraps the mongo.Database.Collection.DeleteOne() method
1211
// It returns the number of affected records and an error
1312
func (l *Link) DeleteOne(database, collection string, filter interface{}) (int64, error) {
14-
if l.client == nil {
15-
return 0, fmt.Errorf("mongohelper is not connected")
13+
if err := l.linkCheck("link.DeleteOne"); err != nil {
14+
return 0, err
1615
}
1716

1817
ctx, cancel := context.WithTimeout(context.Background(), l.execTimeout())

find.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import (
2121
// The filter parameter must be a document containing query operators and can be used to select which documents are
2222
// included in the result. An empty document (e.g. bson.D{}) should be used to include all documents.
2323
func (l *Link) Find(database, collection string, filter interface{}, dest interface{}) error {
24-
if l.client == nil {
25-
return fmt.Errorf("mongohelper is not connected")
24+
if err := l.linkCheck("link.Find"); err != nil {
25+
return err
2626
}
2727

2828
if dest == nil {

findone.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import (
1616
// returned. If the filter does not match any documents, a SingleResult with an error set to
1717
// ErrNoDocuments will be returned. If the filter matches multiple documents, one will be selected from the matched set.
1818
func (l *Link) FindOne(database, collection string, filter interface{}, dest interface{}) error {
19-
if l.client == nil {
20-
return fmt.Errorf("mongohelper is not connected")
19+
if err := l.linkCheck("link.FindOne"); err != nil {
20+
return err
2121
}
2222

2323
if dest == nil {

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ require (
66
github.com/klauspost/compress v1.10.7 // indirect
77
github.com/pkg/errors v0.9.1 // indirect
88
go.mongodb.org/mongo-driver v1.3.3
9-
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 // indirect
9+
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed // indirect
1010
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a // indirect
1111
)

go.sum

+2-4
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,15 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV
7676
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
7777
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo=
7878
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
79-
go.mongodb.org/mongo-driver v1.3.2 h1:IYppNjEV/C+/3VPbhHVxQ4t04eVW0cLp0/pNdW++6Ug=
80-
go.mongodb.org/mongo-driver v1.3.2/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
8179
go.mongodb.org/mongo-driver v1.3.3 h1:9kX7WY6sU/5qBuhm5mdnNWdqaDAQKB2qSZOd5wMEPGQ=
8280
go.mongodb.org/mongo-driver v1.3.3/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
8381
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
8482
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
8583
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
8684
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 h1:8dUaAV7K4uHsF56JQWkprecIQKdPHtR9jCHF5nB8uzc=
8785
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
88-
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
89-
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
86+
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed h1:g4KENRiCMEx58Q7/ecwfT0N2o8z35Fnbsjig/Alf2T4=
87+
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
9088
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
9189
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
9290
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

insertmany.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package mongohelper
33
import (
44
"context"
55
"errors"
6-
"fmt"
76
"go.mongodb.org/mongo-driver/bson/primitive"
87
"go.mongodb.org/mongo-driver/mongo"
98
"go.mongodb.org/mongo-driver/mongo/options"
@@ -12,8 +11,8 @@ import (
1211
// InsertMany wraps the mongo.Database.Collection.InsertMany() method
1312
// It returns an array with generated ObjectIDs and an error
1413
func (l *Link) InsertMany(database, collection string, document []interface{}) ([]string, error) {
15-
if l.client == nil {
16-
return []string{}, fmt.Errorf("mongohelper is not connected")
14+
if err := l.linkCheck("link.InsertMany"); err != nil {
15+
return []string{}, err
1716
}
1817

1918
ctx, cancel := context.WithTimeout(context.Background(), l.execTimeout())

insertone.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package mongohelper
33
import (
44
"context"
55
"errors"
6-
"fmt"
76
"go.mongodb.org/mongo-driver/bson/primitive"
87
"go.mongodb.org/mongo-driver/mongo"
98
"go.mongodb.org/mongo-driver/mongo/options"
@@ -12,8 +11,8 @@ import (
1211
// InsertOne wraps the mongo.Database.Collection.InsertOne() method
1312
// It returns the generated ObjectId and an error
1413
func (l *Link) InsertOne(database, collection string, document interface{}) (string, error) {
15-
if l.client == nil {
16-
return ``, fmt.Errorf("mongohelper is not connected")
14+
if err := l.linkCheck("link.InsertOne"); err != nil {
15+
return "", err
1716
}
1817

1918
ctx, cancel := context.WithTimeout(context.Background(), l.execTimeout())

link.go

+13-85
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
package mongohelper
22

33
import (
4-
"context"
5-
"fmt"
6-
"go.mongodb.org/mongo-driver/mongo"
7-
"go.mongodb.org/mongo-driver/mongo/options"
8-
"go.mongodb.org/mongo-driver/mongo/readpref"
94
"log"
105
"time"
6+
7+
"go.mongodb.org/mongo-driver/mongo"
118
)
129

1310
// Link is a concentrator wrapper for mongodb client
1411
type Link struct {
15-
client *mongo.Client
16-
connectionString string
17-
options Options
12+
client *mongo.Client
13+
options Options
1814
}
1915

2016
// insistOnFail returns l.options.reconnectionInsistOnFail value
@@ -39,7 +35,7 @@ func (l Link) canInsist() bool {
3935
return false
4036
}
4137

42-
// wait N seconds before next 9re)connection attempt
38+
// wait N seconds before next (9)re)connection attempt
4339
func (l Link) wait() {
4440
timeout := time.Duration(l.options.reconnectionSecondsBetweenAttempts) * time.Second
4541

@@ -64,7 +60,7 @@ func (l *Link) notifyConnection() {
6460
}
6561

6662
if l.options.printLogMessages {
67-
log.Println("mongodb connected")
63+
l.log("link.notifyConnection", "mongodb connected")
6864
}
6965
}
7066

@@ -75,86 +71,18 @@ func (l Link) log(routine, message string) {
7571
}
7672
}
7773

78-
// connect tries to conect database using the given options
79-
func (l *Link) connect() error {
80-
var ctx context.Context
81-
82-
// Context with timeout can't be used in loops, because they expire before the loop complete its job
83-
if l.insistOnFail() {
84-
ctx = context.Background()
85-
} else {
86-
timeout := time.Duration(l.options.connectionTimeoutInSeconds) * time.Second
87-
88-
_ctx, cancel := context.WithTimeout(context.Background(), timeout)
89-
90-
ctx = _ctx
91-
92-
defer cancel()
93-
}
94-
95-
for {
96-
var err error
97-
98-
opts := options.Client().ApplyURI(l.connectionString)
99-
opts.SetConnectTimeout(l.connTimeout())
100-
opts.SetMaxConnIdleTime(8 * time.Hour)
101-
opts.SetSocketTimeout(l.execTimeout())
102-
opts.SetMinPoolSize(10)
103-
104-
l.client, err = mongo.Connect(ctx)
105-
106-
if err != nil {
107-
l.log("mongo.Connect", err.Error())
108-
}
109-
110-
err = l.client.Ping(context.Background(), readpref.Primary())
111-
112-
if err != nil {
113-
l.log("mongo.Ping", err.Error())
114-
} else {
115-
l.notifyConnection()
116-
117-
return nil
118-
}
119-
120-
if l.insistOnFail() {
121-
if l.canInsist() {
122-
l.wait()
123-
l.increment()
124-
continue
125-
}
126-
}
74+
func (l Link) appName() string {
75+
return l.options.appName
76+
}
12777

128-
return err
129-
}
78+
func (l Link) connectionString() string {
79+
return l.options.connString
13080
}
13181

13282
func (l Link) connTimeout() time.Duration {
133-
return time.Duration(l.options.connectionTimeoutInSeconds) * time.Second
83+
return time.Duration(l.options.connTimeoutSeconds) * time.Second
13484
}
13585

13686
func (l Link) execTimeout() time.Duration {
137-
return time.Duration(l.options.executionTimeoutInSeconds) * time.Second
138-
}
139-
140-
// quickPing tries to reach the database in 10 seconds
141-
func (l Link) quickPing() error {
142-
ctx, cancel := context.WithTimeout(context.Background(), l.connTimeout())
143-
144-
defer cancel()
145-
146-
return l.client.Ping(ctx, readpref.Primary())
147-
}
148-
149-
// Collection returns a collection from the target database
150-
func (l Link) Collection(database, collection string) (*mongo.Collection, error) {
151-
if l.client == nil {
152-
return nil, fmt.Errorf("use of uninitialized connection")
153-
}
154-
155-
if err := l.quickPing(); err != nil {
156-
return nil, err
157-
}
158-
159-
return l.client.Database(database).Collection(collection), nil
87+
return time.Duration(l.options.execTimeoutSeconds) * time.Second
16088
}

linkcheck.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package mongohelper
2+
3+
import "fmt"
4+
5+
func (l Link) linkCheck(routine string) error {
6+
if l.client == nil {
7+
l.log(routine, "use of uninitialized connection")
8+
9+
return fmt.Errorf("use of uninitialized connection")
10+
}
11+
12+
return nil
13+
}

0 commit comments

Comments
 (0)