Странные ошибки с управлением потоками в ejabberd
Я создаю приложение для обмена мгновенными сообщениями на iOS, которое использует ejabberd. В настоящее время я тестирую функцию управления потоками и, в частности, возобновление, которое работает в большинстве случаев. Однако есть случай, который я не понимаю, что я могу реплицировать с помощью следующих шагов, принимая во внимание настройки: resume_timeout: 30, resend_on_timeout: if_offline
- в начале подключены клиент A и клиент B, другие ресурсы не подключены
- клиент B дает сбой или отключается не чистым способом
- клиент А начинает очень быстро отправлять кучу сообщений (10+)
- ejabberd отправляет подтверждение A для каждого отправленного сообщения, чтобы подтвердить, что сообщения достигли сервера
- примерно через 20 секунд после аварии, B снова подключается. В этот момент А получает сообщение об ошибке для каждого сообщения, отправленного ранее.
<message xmlns="jabber:client" from="clientB@mydomain" to="clientA@mydomain/resourceID" type="error" id="CFBF4583-209A-4453-2567-CCCC7894827E">
<body>test</body>
<active xmlns="http://jabber.org/protocol/chatstates" />
<request xmlns="urn:xmpp:receipts" />
<error code="503" type="cancel">
<service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
</error>
</message>
Я пробовал с ejabberd 16.01.
Это происходит в 80% случаев; иногда сообщения, отправленные А, корректно доставляются В при повторном соединении в течение 30 секунд.
Мои вопросы:
- это поведение правильно? Я ожидал бы, что никакая ошибка не будет возвращена клиенту A, если подтверждение уже получено для сообщения.
- поскольку
resend_on_timeout
установлен вif_offline
и никакой другой ресурс не связан, я не ожидал бы никаких ошибок вообще. Я прав?
2 ответа
- Подтверждения управления потоком указывают только на то, что сообщение получено вашим сервером. Это не означает, что сообщение было обработано или доставлено по указанному адресу. Даже если он был доставлен по адресу, это устройство может вернуть ошибку для раздела.
На самом деле это всего лишь удар в темноте, но после просмотра кода ejabberd может произойти следующее:
clientB@mydomain/ResourceB
сбрасывает соединение, теперь есть сеанс, ожидающий возобновления с помощьюResourceB
,- Клиент B переподключается, не возобновляет работу (потому что он потерпел крах и потерял свое состояние).
- Клиент B связывает ресурс
ResourceB
снова. - Теперь сервер должен завершить сеанс ожидания, который ожидал возобновления, потому что клиент B запросил тот же ресурс.
- Сервер проверяет, есть ли другие сеансы, потому что он установлен в
if_offline
, - Сервер видит, что существует сеанс (новый сеанс), и, следовательно, выбирает сброс, а не повторную отправку.
Так что моя теория такова, что
if_offline
проверяет, существуют ли другие сеансы, когда необходимо обработать очередь неподтвержденных сообщений, а не в момент, когда сообщение было получено изначально.
Ответ @xnyhps правильный, и я исправил этот конкретный случай в следующей версии ejabberd. Тем не менее, @xnyhps также правильно, что есть и другие крайние случаи, поэтому, если вы хотите надежной доставки сообщений, вы должны использовать XEP-0313. Главной особенностью XEP-0198 является возобновление сеанса.