В этих условиях:
- Клиент теряет сетевое подключение к zk.
- Проходит минута.
- Клиент восстанавливает сетевое подключение к zk.
Я получаю следующую панику:
panic: close of closed channel
goroutine 2849 [running]:
github.com/samuel/go-zookeeper/zk.(*Conn).Close(0xc420795180)
github.com/samuel/go-zookeeper/zk/conn.go:253 47
github.com/curator-go/curator.(*handleHolder).internalClose(0xc4203058f0, 0xc420302470, 0x0)
github.com/curator-go/curator/state.go:136 +0x8d
github.com/curator-go/curator.(*handleHolder).closeAndReset(0xc4203058f0, 0xc42587cd00, 0x1e)
github.com/curator-go/curator/state.go:122 +0x2f
github.com/curator-go/curator.(*connectionState).reset(0xc420302420, 0x1b71d87, 0xf)
github.com/curator-go/curator/state.go:234 +0x55
github.com/curator-go/curator.(*connectionState).handleExpiredSession(0xc420302420)
github.com/curator-go/curator/state.go:351 +0xd9
github.com/curator-go/curator.(*connectionState).checkState(0xc420302420, 0xffffff90, 0x0, 0x0, 0xc425ed2600, 0xed0e5250a)
github.com/curator-go/curator/state.go:318 +0x9c
github.com/curator-go/curator.(*connectionState).process(0xc420302420, 0xc425ed2680)
github.com/curator-go/curator/state.go:299 +0x16d
created by github.com/curator-go/curator.(*Watchers).Fire
github.com/curator-go/curator/watcher.go:64 +0x96
Это подробная последовательность событий:
- Клиент теряет сетевое подключение к zk.
- Проходит минута.
- Клиент восстанавливает сетевое подключение к zk.
- goroutine A называет
s.ReregisterAll()
→Conn()
→checkTimeout()
→reset
(bc 1 минута истекло) →closeAndReset()
→conn.Close()
, который может блокировать секунду - goroutine B обрабатывает
zk.StateExpired
(кластер zk отправляет этот bc, он считает этот клиент мертвым, так как он не выполнял ping во время 2.) →reset
→closeAndReset()
→conn.Close()
, что вызывает панику потому чтоconn.Close()
уже закрыл канал соединенияc.shouldQuit
. Иs.zooKeeper.getZookeeperConnection
никогда не вызывался goroutine A, потому что он блокировал второй, поэтому нет нового соединения.
Наивное решение, которое я пробовал, - просто использовать мьютексы на reset
, но теперь я получаю helper.GetConnectionString()
равным пустой строке. Какой лучший способ избежать этого сбоя и попытаться войти в хорошее состояние, когда клиент потеряет, а затем восстановит сетевое подключение? Должно ли исправление быть в github.com/samuel/go-zookeeper, не позволяя закрыть уже закрытое соединение?
(Я написал этот вопрос здесь, но, похоже, проект не хватает в плане обсуждения, поэтому я спрашиваю о SO. )