@@ -378,13 +378,9 @@ func (opts Opts) Clone() Opts {
378
378
//
379
379
// Notes:
380
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 ) {
381
+ // - There will be only one attempt to connect. If multiple attempts needed,
382
+ // Connect could be placed inside the loop with some timeout between each try.
383
+ func Connect (ctx context.Context , addr string , opts Opts ) (conn * Connection , err error ) {
388
384
conn = & Connection {
389
385
addr : addr ,
390
386
requestId : 0 ,
@@ -432,25 +428,8 @@ func Connect(addr string, opts Opts) (conn *Connection, err error) {
432
428
433
429
conn .cond = sync .NewCond (& conn .mutex )
434
430
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
- }
431
+ if err = conn .createConnection (ctx ); err != nil {
432
+ return nil , err
454
433
}
455
434
456
435
go conn .pinger ()
@@ -534,18 +513,11 @@ func (conn *Connection) cancelFuture(fut *Future, err error) {
534
513
}
535
514
}
536
515
537
- func (conn * Connection ) dial () (err error ) {
516
+ func (conn * Connection ) dial (ctx context. Context ) (err error ) {
538
517
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
518
546
519
var c Conn
547
- c , err = conn .opts .Dialer .Dial (conn .addr , DialOpts {
548
- DialTimeout : dialTimeout ,
520
+ c , err = conn .opts .Dialer .Dial (ctx , conn .addr , DialOpts {
549
521
IoTimeout : opts .Timeout ,
550
522
Transport : opts .Transport ,
551
523
Ssl : opts .Ssl ,
@@ -658,34 +630,19 @@ func pack(h *smallWBuf, enc *msgpack.Encoder, reqid uint32,
658
630
return
659
631
}
660
632
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
633
+ func (conn * Connection ) createConnection (ctx context.Context ) error {
634
+ var err error
635
+ if conn .c == nil && conn .state == connDisconnected {
636
+ err = conn .dial (ctx )
637
+ if err == nil {
638
+ conn .notify (Connected )
639
+ return nil
677
640
}
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
641
}
685
642
if conn .state == connClosed {
686
643
err = ClientError {ErrConnectionClosed , "using closed connection" }
687
644
}
688
- return
645
+ return err
689
646
}
690
647
691
648
func (conn * Connection ) closeConnection (neterr error , forever bool ) (err error ) {
@@ -727,11 +684,58 @@ func (conn *Connection) closeConnection(neterr error, forever bool) (err error)
727
684
return
728
685
}
729
686
687
+ func (conn * Connection ) getDialTimeout () time.Duration {
688
+ dialTimeout := conn .opts .Reconnect / 2
689
+ if dialTimeout == 0 {
690
+ dialTimeout = 500 * time .Millisecond
691
+ } else if dialTimeout > 5 * time .Second {
692
+ dialTimeout = 5 * time .Second
693
+ }
694
+ return dialTimeout
695
+ }
696
+
697
+ func (conn * Connection ) runReconnects () error {
698
+ dialTimeout := conn .getDialTimeout ()
699
+ var reconnects uint
700
+ var err error
701
+
702
+ for reconnects <= conn .opts .MaxReconnects {
703
+ now := time .Now ()
704
+
705
+ ctx , cancel := context .WithTimeout (context .Background (), dialTimeout )
706
+ err = conn .createConnection (ctx )
707
+ cancel ()
708
+
709
+ if err == nil {
710
+ return nil
711
+ }
712
+ if clientErr , ok := err .(ClientError ); ok &&
713
+ clientErr .Code == ErrConnectionClosed {
714
+ return err
715
+ }
716
+
717
+ conn .opts .Logger .Report (LogReconnectFailed , conn , reconnects , err )
718
+ conn .notify (ReconnectFailed )
719
+ if conn .opts .MaxReconnects != 0 {
720
+ reconnects ++
721
+ }
722
+ conn .mutex .Unlock ()
723
+
724
+ time .Sleep (time .Until (now .Add (conn .opts .Reconnect )))
725
+
726
+ conn .mutex .Lock ()
727
+ }
728
+
729
+ conn .opts .Logger .Report (LogLastReconnectFailed , conn , err )
730
+ // mark connection as closed to avoid reopening by another goroutine
731
+ return ClientError {ErrConnectionClosed , "last reconnect failed" }
732
+ }
733
+
730
734
func (conn * Connection ) reconnectImpl (neterr error , c Conn ) {
731
735
if conn .opts .Reconnect > 0 {
732
736
if c == conn .c {
733
737
conn .closeConnection (neterr , false )
734
- if err := conn .createConnection ( true ); err != nil {
738
+ if err := conn .runReconnects ( ); err != nil {
735
739
conn .closeConnection (err , true )
736
740
}
737
741
}
0 commit comments