Как избежать двойного соединения при восстановлении соединения?
При этих обстоятельствах:
- Клиент теряет сетевое подключение к 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.
- вызовы А
s.ReregisterAll()
->Conn()
->checkTimeout()
->reset
(BC 1 минута истекла) ->closeAndReset()
->conn.Close()
который может заблокировать на секунду - ручки рутины B
zk.StateExpired
(кластер zk отправляет этот bc, он считает этот клиент мертвым, поскольку он не пинговал в течение 2.) ->reset
->closeAndReset()
->conn.Close()
который вызывает панику, потому чтоconn.Close()
уже закрыл соединениеc.shouldQuit
канал Иs.zooKeeper.getZookeeperConnection
не был вызван goroutine A, потому что он блокировался на секунду, поэтому нового соединения нет.
Наивное решение, которое я попробовал, состоит в том, чтобы просто использовать мьютекс на reset
, но сейчас я получаю helper.GetConnectionString()
равно пустой строке. Какой лучший способ избежать этого сбоя и попытаться войти в хорошее состояние, когда клиент теряет и затем восстанавливает сетевое подключение? Должно ли исправление в реализации http://github.com/samuel/go-zookeeper не разрешать закрывать уже закрытое соединение?
(Я подал эту проблему здесь, но проект, по-видимому, отсутствует в плане обсуждения, поэтому я спрашиваю об этом.)
1 ответ
zk.Conn имеет метод State(), который возвращает перечисление "State", которое является одним из следующих:
type State int32
const (
StateUnknown State = -1
StateDisconnected State = 0
StateConnecting State = 1
StateAuthFailed State = 4
StateConnectedReadOnly State = 5
StateSaslAuthenticated State = 6
StateExpired State = -112
StateConnected = State(100)
StateHasSession = State(101)
)
В каком состоянии находится "conn", когда в программе B вызывается conn.Close()?
Возможным решением было бы добавить коммутатор в программу B, при котором вы не вызываете conn.Close (), если вы находитесь в conn.StateConnecting.