В КУРСЕ?

Разбираемся в теме

Отмена работы в Go: как связать горутины с жизненным циклом запроса

Запустить горутину проще, чем объяснить, кто и когда должен её остановить. Запрос уже завершился, клиент отключился, результат больше никому не нужен, а фоновая операция продолжает ждать ответ или отправлять данные в канал. Поэтому проектирование конкурентной работы начинается с вопроса о её владельце. Этот вопрос полезен и разработчику, и человеку, который проверяет техническое решение команды.

У каждой операции должен быть владелец

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

Сигнал отмены требует реакции

Контекст передаёт срок, сигнал отмены и связанные с запросом значения. Он не уничтожает горутину принудительно. Код должен передать его поддерживающей отмену операции или самостоятельно проверить сигнал в подходящем месте. Особенно важно ожидание отправки в канал: если получатель ушёл, обычная отправка может ждать бесконечно. Возможность выбрать между отправкой и отменой делает выход явным. При создании дочернего контекста с функцией отмены её вызывают после завершения работы, освобождая связанные ресурсы.

Завершение состоит из нескольких договорённостей

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

Проверяйте неприятные сценарии

Успешный ответ проверяет лишь один путь исполнения. В ревью стоит проследить раннюю ошибку одного исполнителя, медленного получателя, отмену до первого результата и исчерпание срока ожидания. Для каждого ожидания задайте вопрос: какое событие позволит выйти? Добавление буфера иногда переносит проблему на больший объём данных, но не определяет жизненный цикл. Наблюдаемость тоже должна различать ошибку сервиса и отмену со стороны клиента, иначе нормальные прекращения работы создадут вводящие в заблуждение сигналы.

Попробуйте на практике

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

  1. Нарисуйте обработчик, два исполнителя и канал результатов. Подпишите владельца каждой горутины и того, кто закрывает канал.
  2. Отметьте все ожидания: внешний ответ, отправку результата, получение результата и завершение исполнителей.
  3. Проиграйте три случая: полный успех, ошибка первого исполнителя, отмена запроса до ответа второго.
  4. Для каждого случая запишите, кто подаёт отмену, кто её замечает и как обработчик узнаёт о завершении работы.

Как проверить результат. У каждого ожидания есть понятный путь выхода; канал закрывает определённый владелец после окончания отправок, а отмена не принимается за доказательство завершения.

Частые вопросы

Нужен ли новый контекст для каждой функции?

Обычно передают контекст соответствующей операции. Новый дочерний контекст нужен при дополнительной границе времени или отдельной возможности отменить часть работы.

Можно ли решить всё увеличением буфера?

Буфер уменьшает зависимость от кратковременной скорости потребителя, но остаётся конечным. Он не заменяет правила отмены, закрытия и ожидания завершения.

Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.

Зарегистрируйтесь, чтобы уточнить возможность доступа к этому материалу

Зарегистрироваться
← К списку материалов