Codebase list golang-github-go-kit-kit / 9aa632b
util/conn: reconnect when initial Dial fails Peter Bourgon 7 years ago
2 changed file(s) with 39 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
6666 func (m *Manager) loop() {
6767 var (
6868 conn = dial(m.dialer, m.network, m.address, m.logger) // may block slightly
69 connc = make(chan net.Conn)
69 connc = make(chan net.Conn, 1)
7070 reconnectc <-chan time.Time // initially nil
7171 backoff = time.Second
7272 )
73
74 // If the initial dial fails, we need to trigger a reconnect via the loop
75 // body, below. If we did this in a goroutine, we would race on the conn
76 // variable. So we use a buffered chan instead.
77 connc <- conn
7378
7479 for {
7580 select {
9090 }
9191 }
9292
93 func TestIssue292(t *testing.T) {
94 // The util/conn.Manager won't attempt to reconnect to the provided endpoint
95 // if the endpoint is initially unavailable (e.g. dial tcp :8080:
96 // getsockopt: connection refused). If the endpoint is up when
97 // conn.NewManager is called and then goes down/up, it reconnects just fine.
98
99 var (
100 tickc = make(chan time.Time)
101 after = func(time.Duration) <-chan time.Time { return tickc }
102 dialconn = net.Conn(nil)
103 dialerr = errors.New("fail")
104 dialer = func(string, string) (net.Conn, error) { return dialconn, dialerr }
105 mgr = NewManager(dialer, "netw", "addr", after, log.NewNopLogger())
106 )
107
108 if conn := mgr.Take(); conn != nil {
109 t.Fatal("first Take should have yielded nil conn, but didn't")
110 }
111
112 dialconn, dialerr = &mockConn{}, nil
113 select {
114 case tickc <- time.Now():
115 case <-time.After(time.Second):
116 t.Fatal("manager isn't listening for a tick, despite a failed dial")
117 }
118
119 if !within(time.Second, func() bool {
120 return mgr.Take() != nil
121 }) {
122 t.Fatal("second Take should have yielded good conn, but didn't")
123 }
124 }
125
93126 type mockConn struct {
94127 rd, wr uint64
95128 }