Тайм-аут пинга Websocket замораживает бота Mattermost

Я создаю бота Mattermost. Он перестает отвечать после того, как соединение через веб-сокет получает тайм-аут пинга (PingTimeoutChannel) после случайных периодов времени (1 минута, 8 минут, 2 часа и т. д.). Сервер Mattermost v.5.13, API v.4.

Бот подключается к Mattermost API, создавая новый Client4. Затем он входит в систему как пользователь и после этого создает клиент Websocket с полученным токеном авторизации. Он начинает слушать на всех каналах, и когда он получает событие, которое является сообщением, адресованным ему (@botname), он автоматически отвечает (создает model.post).

Я решил использовать простую аутентификацию по имени пользователя/паролю для входа в систему, как и в образце бота Mattermost. Однако я попытался переписать его на аутентификацию токена личного доступа (как в здесь), потому что я думал, что это решит проблему тайм-аута. Однако это решение больше не работает, оно выдает «Ошибка недействительного или просроченного сеанса, пожалуйста, войдите снова» при попытке войти в систему таким образом.

Поэтому я отказался от этой идеи и начал искать, где происходит тайм-аут. Пинг сервера в порядке, вебсокета нет. Я пробовал много способов, вплоть до того, что просто переподключился (снова создав новые клиенты Mattermost API и Websocket). Бот по-прежнему не отвечает. У меня закончились идеи.

Соединение через веб-сокет (обработка ошибок пропущена):

    if config.BotCfg.Port == "443" {
        protocol = "https"
        secure = true
    }

        config.ConnectionCfg.Client = model.NewAPIv4Client(fmt.Sprintf("%s://%s:%s", protocol, config.BotCfg.Server, config.BotCfg.Port))


    user,resp := config.ConnectionCfg.Client.Login(config.BotCfg.BotName, config.BotCfg.Password)

    setBotTeam()

    if limit.Users == nil {
        limit.SetUsersList()
    }

    ws := "ws"
    if secure {
        ws = "wss"
    }

    if Websocket != nil {
        Websocket.Close()
    }

    websocket, err := model.NewWebSocketClient4(fmt.Sprintf("%s://%s:%s", ws, config.BotCfg.Server, config.BotCfg.Port), config.ConnectionCfg.Client.AuthToken)

Функция прослушивания:

        for {
            select {

            case <-connection.Websocket.PingTimeoutChannel:
                logs.WriteToFile("Websocket ping timeout. Connecting again.")
                log.Println("Websocket ping timeout. Connecting again.")
                mux.Lock()
                connection.Connect()
                mux.Unlock()

            case event := <-connection.Websocket.EventChannel:
                mux.Lock()
                if event != nil {
                    if event.IsValid() && isMessage(event.Event){
                        handleEvent(event)
                    }
                }
                mux.Unlock()
            }
        }
    }()
    // block to the go function
    select {}

Я ожидаю, что бот будет работать непрерывно. Если у вас есть какие-либо предложения, как решить эту проблему, я был бы очень признателен!

Изменить: как предложил Cerise, я добавил SIGQUIT в функцию выхода и запустил детектор гонки. Исправлена ​​проблема с гонкой данных, удалив один if из события case := [...]. Детектор гонки больше не сообщает о каких-либо проблемах, однако бот по-прежнему перестает отвечать через некоторое время.

Я обнаружил, что при первом возникновении PingTimeout одноранговый узел перестает отвечать, пока я не перезапущу приложение. Переподключение Websocket не помогает. Однако я на самом деле не знаю, как решить эту проблему, или решение вообще существует.


person gabkub    schedule 23.07.2019    source источник
comment
Запустите программу с помощью детектора гонки и устраните все проблемы. Опишите подробнее, что делает программа, когда перестала отвечать. Он заблокирован при выборе в вопросе или где-то еще? Если вы не знаете, что делает программа, сбросьте стеки горутин, завершив программу сигналом SIGQUIT.   -  person Cerise Limón    schedule 23.07.2019