Skip to content

Commit ff7346d

Browse files
committed
api: add context to connection create
`connection.Connect` and `pool.Connect` no longer return non-working connection objects. Those functions now accept context as their first arguments, which user may cancel in process. `connection.Connect` will block until either the working connection created (and returned), `opts.MaxReconnects` creation attempts were made (returns error) or the context is canceled by user (returns error too). Closes #136
1 parent d8df65d commit ff7346d

24 files changed

+268
-140
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
2828
decoded to a varbinary object (#313).
2929
- Use objects of the Decimal type instead of pointers (#238)
3030
- Use objects of the Datetime type instead of pointers (#238)
31+
- `connection.Connect` and `pool.Connect` no longer return non-working
32+
connection objects (#136). Those functions now accept context as their first
33+
arguments, which user may cancel in process.
3134

3235
### Deprecated
3336

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,15 @@ about what it does.
105105
package tarantool
106106

107107
import (
108+
"context"
108109
"fmt"
109110
"github.com/tarantool/go-tarantool/v2"
110111
)
111112

112113
func main() {
113114
opts := tarantool.Opts{User: "guest"}
114-
conn, err := tarantool.Connect("127.0.0.1:3301", opts)
115+
ctx := context.Background()
116+
conn, err := tarantool.Connect(ctx, "127.0.0.1:3301", opts)
115117
if err != nil {
116118
fmt.Println("Connection refused:", err)
117119
}

connection.go

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -381,10 +381,11 @@ func (opts Opts) Clone() Opts {
381381
// - If opts.Reconnect is zero (default), then connection either already connected
382382
// or error is returned.
383383
//
384-
// - If opts.Reconnect is non-zero, then error will be returned only if authorization
385-
// fails. But if Tarantool is not reachable, then it will make an attempt to reconnect later
386-
// and will not finish to make attempts on authorization failures.
387-
func Connect(addr string, opts Opts) (conn *Connection, err error) {
384+
// - If opts.Reconnect is non-zero, then error will be returned if authorization
385+
// fails, or user has canceled context. If Tarantool is not reachable, then it
386+
// will make attempts to reconnect and will not finish to make attempts on
387+
// authorization failures.
388+
func Connect(ctx context.Context, addr string, opts Opts) (conn *Connection, err error) {
388389
conn = &Connection{
389390
addr: addr,
390391
requestId: 0,
@@ -432,7 +433,7 @@ func Connect(addr string, opts Opts) (conn *Connection, err error) {
432433

433434
conn.cond = sync.NewCond(&conn.mutex)
434435

435-
if err = conn.createConnection(false); err != nil {
436+
if err = conn.createConnection(ctx, false); err != nil {
436437
ter, ok := err.(Error)
437438
if conn.opts.Reconnect <= 0 {
438439
return nil, err
@@ -441,15 +442,12 @@ func Connect(addr string, opts Opts) (conn *Connection, err error) {
441442
// Reported auth errors immediately.
442443
return nil, err
443444
} else {
444-
// Without SkipSchema it is useless.
445-
go func(conn *Connection) {
446-
conn.mutex.Lock()
447-
defer conn.mutex.Unlock()
448-
if err := conn.createConnection(true); err != nil {
449-
conn.closeConnection(err, true)
450-
}
451-
}(conn)
452-
err = nil
445+
conn.mutex.Lock()
446+
defer conn.mutex.Unlock()
447+
if err := conn.createConnection(ctx, true); err != nil {
448+
conn.closeConnection(err, true)
449+
return nil, err
450+
}
453451
}
454452
}
455453

@@ -658,7 +656,8 @@ func pack(h *smallWBuf, enc *msgpack.Encoder, reqid uint32,
658656
return
659657
}
660658

661-
func (conn *Connection) createConnection(reconnect bool) (err error) {
659+
func (conn *Connection) createConnection(ctx context.Context,
660+
reconnect bool) (err error) {
662661
var reconnects uint
663662
for conn.c == nil && conn.state == connDisconnected {
664663
now := time.Now()
@@ -679,7 +678,20 @@ func (conn *Connection) createConnection(reconnect bool) (err error) {
679678
conn.notify(ReconnectFailed)
680679
reconnects++
681680
conn.mutex.Unlock()
682-
time.Sleep(time.Until(now.Add(conn.opts.Reconnect)))
681+
682+
timer := time.NewTimer(time.Until(now.Add(conn.opts.Reconnect)))
683+
waitLoop:
684+
for {
685+
select {
686+
case <-ctx.Done():
687+
err = ClientError{ErrConnectionClosed, "context is canceled"}
688+
conn.mutex.Lock()
689+
return
690+
case <-timer.C:
691+
break waitLoop
692+
}
693+
}
694+
683695
conn.mutex.Lock()
684696
}
685697
if conn.state == connClosed {
@@ -731,7 +743,7 @@ func (conn *Connection) reconnectImpl(neterr error, c Conn) {
731743
if conn.opts.Reconnect > 0 {
732744
if c == conn.c {
733745
conn.closeConnection(neterr, false)
734-
if err := conn.createConnection(true); err != nil {
746+
if err := conn.createConnection(context.Background(), true); err != nil {
735747
conn.closeConnection(err, true)
736748
}
737749
}

crud/example_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package crud_test
22

33
import (
4+
"context"
45
"fmt"
56
"reflect"
67
"time"
@@ -21,7 +22,7 @@ var exampleOpts = tarantool.Opts{
2122
}
2223

2324
func exampleConnect() *tarantool.Connection {
24-
conn, err := tarantool.Connect(exampleServer, exampleOpts)
25+
conn, err := tarantool.Connect(context.Background(), exampleServer, exampleOpts)
2526
if err != nil {
2627
panic("Connection is not established: " + err.Error())
2728
}

crud/tarantool_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package crud_test
22

33
import (
4+
"context"
45
"fmt"
56
"log"
67
"os"
@@ -108,7 +109,7 @@ var object = crud.MapObject{
108109

109110
func connect(t testing.TB) *tarantool.Connection {
110111
for i := 0; i < 10; i++ {
111-
conn, err := tarantool.Connect(server, opts)
112+
conn, err := tarantool.Connect(context.Background(), server, opts)
112113
if err != nil {
113114
t.Fatalf("Failed to connect: %s", err)
114115
}

datetime/example_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package datetime_test
1010

1111
import (
12+
"context"
1213
"fmt"
1314
"time"
1415

@@ -23,7 +24,7 @@ func Example() {
2324
User: "test",
2425
Pass: "test",
2526
}
26-
conn, err := tarantool.Connect("127.0.0.1:3013", opts)
27+
conn, err := tarantool.Connect(context.Background(), "127.0.0.1:3013", opts)
2728
if err != nil {
2829
fmt.Printf("Error in connect is %v", err)
2930
return

decimal/example_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package decimal_test
1010

1111
import (
12+
"context"
1213
"log"
1314
"time"
1415

@@ -28,7 +29,7 @@ func Example() {
2829
User: "test",
2930
Pass: "test",
3031
}
31-
client, err := tarantool.Connect(server, opts)
32+
client, err := tarantool.Connect(context.Background(), server, opts)
3233
if err != nil {
3334
log.Fatalf("Failed to connect: %s", err.Error())
3435
}

dial_test.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package tarantool_test
22

33
import (
44
"bytes"
5+
"context"
56
"errors"
67
"net"
78
"sync"
@@ -29,9 +30,10 @@ func TestDialer_Dial_error(t *testing.T) {
2930
err: errors.New(errMsg),
3031
}
3132

32-
conn, err := tarantool.Connect("any", tarantool.Opts{
33-
Dialer: dialer,
34-
})
33+
conn, err := tarantool.Connect(context.Background(), "any",
34+
tarantool.Opts{
35+
Dialer: dialer,
36+
})
3537
assert.Nil(t, conn)
3638
assert.ErrorContains(t, err, errMsg)
3739
}
@@ -73,7 +75,7 @@ func TestDialer_Dial_passedOpts(t *testing.T) {
7375
}
7476

7577
dialer := &mockPassedDialer{}
76-
conn, err := tarantool.Connect(addr, tarantool.Opts{
78+
conn, err := tarantool.Connect(context.Background(), addr, tarantool.Opts{
7779
Dialer: dialer,
7880
Timeout: opts.IoTimeout,
7981
Transport: opts.Transport,
@@ -203,11 +205,12 @@ func dialIo(t *testing.T,
203205
dialer := mockIoDialer{
204206
init: init,
205207
}
206-
conn, err := tarantool.Connect("any", tarantool.Opts{
207-
Dialer: &dialer,
208-
Timeout: 1000 * time.Second, // Avoid pings.
209-
SkipSchema: true,
210-
})
208+
conn, err := tarantool.Connect(context.Background(), "any",
209+
tarantool.Opts{
210+
Dialer: &dialer,
211+
Timeout: 1000 * time.Second, // Avoid pings.
212+
SkipSchema: true,
213+
})
211214
require.Nil(t, err)
212215
require.NotNil(t, conn)
213216

example_custom_unpacking_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tarantool_test
22

33
import (
4+
"context"
45
"fmt"
56
"log"
67
"time"
@@ -84,7 +85,7 @@ func Example_customUnpacking() {
8485
User: "test",
8586
Pass: "test",
8687
}
87-
conn, err := tarantool.Connect(server, opts)
88+
conn, err := tarantool.Connect(context.Background(), server, opts)
8889
if err != nil {
8990
log.Fatalf("Failed to connect: %s", err.Error())
9091
}

example_test.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ type Tuple struct {
1919
}
2020

2121
func exampleConnect(opts tarantool.Opts) *tarantool.Connection {
22-
conn, err := tarantool.Connect(server, opts)
22+
conn, err := tarantool.Connect(context.Background(), server, opts)
2323
if err != nil {
2424
panic("Connection is not established: " + err.Error())
2525
}
@@ -38,7 +38,7 @@ func ExampleSslOpts() {
3838
CaFile: "testdata/ca.crt",
3939
},
4040
}
41-
_, err := tarantool.Connect("127.0.0.1:3013", opts)
41+
_, err := tarantool.Connect(context.Background(), "127.0.0.1:3013", opts)
4242
if err != nil {
4343
panic("Connection is not established: " + err.Error())
4444
}
@@ -913,12 +913,13 @@ func ExampleFuture_GetIterator() {
913913
}
914914

915915
func ExampleConnect() {
916-
conn, err := tarantool.Connect("127.0.0.1:3013", tarantool.Opts{
917-
Timeout: 5 * time.Second,
918-
User: "test",
919-
Pass: "test",
920-
Concurrency: 32,
921-
})
916+
conn, err := tarantool.Connect(context.Background(), "127.0.0.1:3013",
917+
tarantool.Opts{
918+
Timeout: 5 * time.Second,
919+
User: "test",
920+
Pass: "test",
921+
Concurrency: 32,
922+
})
922923
if err != nil {
923924
fmt.Println("No connection available")
924925
return
@@ -1081,7 +1082,7 @@ func ExampleConnection_NewPrepared() {
10811082
User: "test",
10821083
Pass: "test",
10831084
}
1084-
conn, err := tarantool.Connect(server, opts)
1085+
conn, err := tarantool.Connect(context.Background(), server, opts)
10851086
if err != nil {
10861087
fmt.Printf("Failed to connect: %s", err.Error())
10871088
}
@@ -1127,7 +1128,7 @@ func ExampleConnection_NewWatcher() {
11271128
Features: []tarantool.ProtocolFeature{tarantool.WatchersFeature},
11281129
},
11291130
}
1130-
conn, err := tarantool.Connect(server, opts)
1131+
conn, err := tarantool.Connect(context.Background(), server, opts)
11311132
if err != nil {
11321133
fmt.Printf("Failed to connect: %s\n", err)
11331134
return

0 commit comments

Comments
 (0)