Как избежать двойного соединения при восстановлении соединения?

При этих обстоятельствах:

  1. Клиент теряет сетевое подключение к zk.
  2. Проходит одна минута.
  3. Клиент восстанавливает сетевое подключение к 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

Это подробная последовательность событий:

  1. Клиент теряет сетевое подключение к zk.
  2. Проходит одна минута.
  3. Клиент восстанавливает сетевое подключение к zk.
  4. вызовы А s.ReregisterAll() -> Conn() -> checkTimeout() -> reset (BC 1 минута истекла) -> closeAndReset() -> conn.Close() который может заблокировать на секунду
  5. ручки рутины 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.

Другие вопросы по тегам