util/conn: reconnect when initial Dial fails
Peter Bourgon
7 years ago
66 | 66 |
func (m *Manager) loop() {
|
67 | 67 |
var (
|
68 | 68 |
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)
|
70 | 70 |
reconnectc <-chan time.Time // initially nil
|
71 | 71 |
backoff = time.Second
|
72 | 72 |
)
|
|
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
|
73 | 78 |
|
74 | 79 |
for {
|
75 | 80 |
select {
|
90 | 90 |
}
|
91 | 91 |
}
|
92 | 92 |
|
|
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 |
|
93 | 126 |
type mockConn struct {
|
94 | 127 |
rd, wr uint64
|
95 | 128 |
}
|