@@ -375,16 +375,7 @@ func (opts Opts) Clone() Opts {
375
375
// - Unix socket, first '/' or '.' indicates Unix socket
376
376
// (unix:///abs/path/tnt.sock, unix:path/tnt.sock, /abs/path/tnt.sock,
377
377
// ./rel/path/tnt.sock, unix/:path/tnt.sock)
378
- //
379
- // Notes:
380
- //
381
- // - If opts.Reconnect is zero (default), then connection either already connected
382
- // or error is returned.
383
- //
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 ) {
378
+ func Connect (ctx context.Context , addr string , opts Opts ) (conn * Connection , err error ) {
388
379
conn = & Connection {
389
380
addr : addr ,
390
381
requestId : 0 ,
@@ -432,25 +423,8 @@ func Connect(addr string, opts Opts) (conn *Connection, err error) {
432
423
433
424
conn .cond = sync .NewCond (& conn .mutex )
434
425
435
- if err = conn .createConnection (false ); err != nil {
436
- ter , ok := err .(Error )
437
- if conn .opts .Reconnect <= 0 {
438
- return nil , err
439
- } else if ok && (ter .Code == iproto .ER_NO_SUCH_USER ||
440
- ter .Code == iproto .ER_CREDS_MISMATCH ) {
441
- // Reported auth errors immediately.
442
- return nil , err
443
- } 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
453
- }
426
+ if err = conn .createConnection (ctx ); err != nil {
427
+ return nil , err
454
428
}
455
429
456
430
go conn .pinger ()
@@ -534,18 +508,11 @@ func (conn *Connection) cancelFuture(fut *Future, err error) {
534
508
}
535
509
}
536
510
537
- func (conn * Connection ) dial () ( err error ) {
511
+ func (conn * Connection ) dial (ctx context. Context ) error {
538
512
opts := conn .opts
539
- dialTimeout := opts .Reconnect / 2
540
- if dialTimeout == 0 {
541
- dialTimeout = 500 * time .Millisecond
542
- } else if dialTimeout > 5 * time .Second {
543
- dialTimeout = 5 * time .Second
544
- }
545
513
546
514
var c Conn
547
- c , err = conn .opts .Dialer .Dial (conn .addr , DialOpts {
548
- DialTimeout : dialTimeout ,
515
+ c , err := conn .opts .Dialer .Dial (ctx , conn .addr , DialOpts {
549
516
IoTimeout : opts .Timeout ,
550
517
Transport : opts .Transport ,
551
518
Ssl : opts .Ssl ,
@@ -555,7 +522,7 @@ func (conn *Connection) dial() (err error) {
555
522
Password : opts .Pass ,
556
523
})
557
524
if err != nil {
558
- return
525
+ return err
559
526
}
560
527
561
528
conn .Greeting .Version = c .Greeting ().Version
@@ -605,7 +572,7 @@ func (conn *Connection) dial() (err error) {
605
572
conn .shutdownWatcher = watcher
606
573
}
607
574
608
- return
575
+ return nil
609
576
}
610
577
611
578
func pack (h * smallWBuf , enc * msgpack.Encoder , reqid uint32 ,
@@ -658,34 +625,18 @@ func pack(h *smallWBuf, enc *msgpack.Encoder, reqid uint32,
658
625
return
659
626
}
660
627
661
- func (conn * Connection ) createConnection (reconnect bool ) (err error ) {
662
- var reconnects uint
663
- for conn .c == nil && conn .state == connDisconnected {
664
- now := time .Now ()
665
- err = conn .dial ()
666
- if err == nil || ! reconnect {
667
- if err == nil {
668
- conn .notify (Connected )
669
- }
670
- return
671
- }
672
- if conn .opts .MaxReconnects > 0 && reconnects > conn .opts .MaxReconnects {
673
- conn .opts .Logger .Report (LogLastReconnectFailed , conn , err )
674
- err = ClientError {ErrConnectionClosed , "last reconnect failed" }
675
- // mark connection as closed to avoid reopening by another goroutine
676
- return
628
+ func (conn * Connection ) createConnection (ctx context.Context ) error {
629
+ var err error
630
+ if conn .c == nil && conn .state == connDisconnected {
631
+ if err = conn .dial (ctx ); err == nil {
632
+ conn .notify (Connected )
633
+ return nil
677
634
}
678
- conn .opts .Logger .Report (LogReconnectFailed , conn , reconnects , err )
679
- conn .notify (ReconnectFailed )
680
- reconnects ++
681
- conn .mutex .Unlock ()
682
- time .Sleep (time .Until (now .Add (conn .opts .Reconnect )))
683
- conn .mutex .Lock ()
684
635
}
685
636
if conn .state == connClosed {
686
637
err = ClientError {ErrConnectionClosed , "using closed connection" }
687
638
}
688
- return
639
+ return err
689
640
}
690
641
691
642
func (conn * Connection ) closeConnection (neterr error , forever bool ) (err error ) {
@@ -727,11 +678,57 @@ func (conn *Connection) closeConnection(neterr error, forever bool) (err error)
727
678
return
728
679
}
729
680
681
+ func (conn * Connection ) getDialTimeout () time.Duration {
682
+ dialTimeout := conn .opts .Reconnect / 2
683
+ if dialTimeout == 0 {
684
+ dialTimeout = 500 * time .Millisecond
685
+ } else if dialTimeout > 5 * time .Second {
686
+ dialTimeout = 5 * time .Second
687
+ }
688
+ return dialTimeout
689
+ }
690
+
691
+ func (conn * Connection ) runReconnects () error {
692
+ dialTimeout := conn .getDialTimeout ()
693
+ var reconnects uint
694
+ var err error
695
+
696
+ for conn .opts .MaxReconnects == 0 || reconnects <= conn .opts .MaxReconnects {
697
+ now := time .Now ()
698
+
699
+ ctx , cancel := context .WithTimeout (context .Background (), dialTimeout )
700
+ err = conn .createConnection (ctx )
701
+ cancel ()
702
+
703
+ if err != nil {
704
+ if clientErr , ok := err .(ClientError ); ok &&
705
+ clientErr .Code == ErrConnectionClosed {
706
+ return err
707
+ }
708
+ } else {
709
+ return nil
710
+ }
711
+
712
+ conn .opts .Logger .Report (LogReconnectFailed , conn , reconnects , err )
713
+ conn .notify (ReconnectFailed )
714
+ reconnects ++
715
+ conn .mutex .Unlock ()
716
+
717
+ time .Sleep (time .Until (now .Add (conn .opts .Reconnect )))
718
+
719
+ conn .mutex .Lock ()
720
+ }
721
+
722
+ conn .opts .Logger .Report (LogLastReconnectFailed , conn , err )
723
+ // mark connection as closed to avoid reopening by another goroutine
724
+ return ClientError {ErrConnectionClosed , "last reconnect failed" }
725
+ }
726
+
730
727
func (conn * Connection ) reconnectImpl (neterr error , c Conn ) {
731
728
if conn .opts .Reconnect > 0 {
732
729
if c == conn .c {
733
730
conn .closeConnection (neterr , false )
734
- if err := conn .createConnection ( true ); err != nil {
731
+ if err := conn .runReconnects ( ); err != nil {
735
732
conn .closeConnection (err , true )
736
733
}
737
734
}
0 commit comments