Skip to content

Обработчик потока выполняется внутри приёмного цикла: медленный подписчик останавливает всё соединение #105

Description

@Platonenkov

Наблюдение

Приёмный цикл ожидает завершения пользовательского обработчика прямо внутри себя — Xrpl/Client/connection.cs, диспетчеризация потоков:

// строка ~3049
if (OnLedgerClosed is not null)
    await OnLedgerClosed.Invoke(response)!;

// строка ~3069
if (OnTransaction is not null)
    await OnTransaction.Invoke(response)!;

То же и для OnValidationReceived рядом.

Почему это проблема

Обработчик подписчика становится частью критического пути соединения. Пока он выполняется, цикл не читает следующее сообщение — а по этому же соединению идут обычные запросы-ответы.

Практические следствия:

  • обработчик, делающий что-либо небыстрое (запись в БД, сетевой вызов, ожидание блокировки), задерживает не только поток, но и все параллельные запросы на том же клиенте;
  • при активной подписке на transactions сообщения приходят непрерывно, поэтому даже небольшая задержка на сообщение накапливается и рано или поздно упирается в таймаут запроса;
  • обработчик, который завис или упал в дедлок, полностью останавливает соединение, при этом внешне оно выглядит живым.

Отдельная сторона того же — отсутствие определённой семантики при отставании подписчика. Сейчас поведение «медленный потребитель» не описано ни в контракте, ни в доках: неизвестно, ждёт ли SDK, теряет ли сообщения, растёт ли где-то очередь.

Ожидаемое

Доставка сообщений потока развязана с приёмным циклом, и поведение при отставании подписчика определено явно. Разумные варианты (выбор за реализацией):

  • очередь с ограничением (System.Threading.Channels) и заданной политикой переполнения — ждать, отбрасывать старые или отбрасывать новые, но выбор задокументирован и по возможности настраиваем;
  • либо явно оставить синхронную доставку, но задокументировать её как контракт: «обработчик обязан возвращать управление немедленно, вся работа — за его пределами».

Второе дешевле и тоже приемлемо. Неприемлемо нынешнее состояние, где семантика не описана, а цена медленного обработчика — остановка всего соединения.

Связь с другими issue

Если контракт подписки будет выведен на IXrplClient (#103), выбранная там форма доставки фактически решает и этот вопрос — их разумно рассматривать вместе. Но дефект существует и сегодня, независимо от того, через что подписываться.

Проверка

Тест с намеренно медленным обработчиком: обычные запросы на том же соединении продолжают отвечать в разумное время, поведение потока соответствует задокументированному.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions