Избегайте великих «Что, черт возьми, случилось с моей сопрограммой??» вопрос

Корутины — отличное решение для многопоточности в проектах вместо необходимости управлять нашими пулами потоков и сопутствующим шаблоном. Однако кривая обучения не так проста, и последствия могут быть ужасными.

Нюанс, о котором я хочу рассказать сегодня, — это великолепный CoroutineExceptionHandler. Вы знаете… это то, что вам нужно, когда вы спрашиваете себя: Что, черт возьми, случилось с моей сопрограммой из-за неперехваченного исключения. Благодаря коллеге я научился раньше, чем позже запускать свои области сопрограмм с обработчиком исключений, чтобы мы могли, по крайней мере, знать, что произошло, если проблема возникнет во время производства. ОДНАКО… я столкнулся с ситуацией, из-за которой я все еще задавал вопросы богам WTF о моей сопрограмме.

После включения моего обработчика исключений я начинаю замечать, что область сопрограммы больше не работает. На мой взгляд, у Хьюстона была большая проблема из-за неудачного запуска (… и это будет моя последняя попытка каламбура). Документация гласит,

Вы не можете восстановиться после исключения в CoroutineExceptionHandler. Сопрограмма уже завершилась с соответствующим исключением, когда вызывается обработчик. — Котлин Документы

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

Если вы хотите по-прежнему использовать область сопрограммы после обработки неперехваченного исключения, вы должны выполнить еще одно действие!

Решение

Во время моего расследования я нашел один способ выйти из этой ситуации, чтобы позволить остальной части моего класса продолжать использовать область действия сопрограммы. Ниже приведены три различных подхода к решению проблемы. В дополнение к показу кода я хотел бы предоставить визуализацию для иллюстрации поведения.

Подход 1: повторная инициализация CoroutineScope

Подход 2: отмените CoroutineScope, чтобы отменить задание и его дочерние элементы

Подход 3: отменить только CoroutineScope

Демонстрация ниже покажет поведение каждого подхода в следующем сценарии.

  • Запустите области сопрограммы, чтобы начать подпрыгивать шариками, указывающими на выполнение кода.
  • Создайте неперехваченное исключение в каждой области действия сопрограммы. (Мячи перестанут прыгать.)
  • Снова запустите области сопрограммы, чтобы возобновить подпрыгивание мячей, указывая на то, что области сопрограммы все еще работают. (Мячи возобновят отскок, если обращаться с ними правильно.)

Ответ богов WTF на мой вопрос

Основываясь на представленной выше визуализации, я предлагаю следующий совет.

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

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

Я хотел бы получить отзывы об идее предоставления визуализаций для иллюстрации поведения сопрограмм. В этой серии «Визуализация сопрограмм» я надеюсь предоставить полезную информацию по этому не столь прямому предмету для нас, визуалов и тех, кто просто ценит это, а не текст.

Демонстрационный проект можно найти здесь: GitHub