Завершение процесса Erlang: где / когда это происходит?
Рассмотрим процессы, все связанные в дереве, либо формальное дерево надзора, либо некоторую специальную структуру.
Теперь рассмотрим какого-нибудь ребенка или работника в этом дереве, с родителем или супервайзером над ним. У меня два вопроса.
Мы хотели бы "изящно" выйти из этого процесса, если его нужно убить или закрыть, потому что он может быть на полпути через обновление некоторого баланса аккаунта. Предположим, что мы должным образом закодировали некоторые функции завершения и связали этот процесс с другими с надлежащим подключением. Теперь предположим, что этот процесс в основном цикле выполняет свою работу. Приходит сигнал о прекращении. Где именно (или, возможно, вопрос должен быть КОГДА ТОЧНО) происходит это прекращение? Другими словами, когда прекратятся звонки? Будет ли объект выгружаться прямо в середине цикла, в котором он запущен, и вызов завершается? Будет ли он ждать до конца цикла, но до повторного запуска цикла? Будет ли он делать это только в режиме приема? И т.п.
Тот же вопрос, но без кодирования функции завершения. Предположим, что родительский процесс является супервизором, и этот дочерний процесс следует обычным соглашениям OTP. Родитель говорит ребенку отключиться, или родительский сбой или что-то еще. Ребенок находится в своей основной петле. Когда / где / как происходит отключение? В середине основного цикла? После этого? И т.п.
1 ответ
Это довольно хорошо объяснено в документах (разделы 12.4, 12.5, 12.6, 12.7).
Есть два случая:
- Ваш процесс завершен из-за плохой логики.
Выдает ошибку, поэтому может оказаться в середине работы, а это может быть плохо. Если вы хотите предотвратить это, вы можете попытаться определить механизм, который включает в себя два процесса. Первый начинает транзакцию, второй выполняет фактическую работу, а после этого первый фиксирует изменения. Если что-то плохое случается со вторым процессом (он умирает из-за ошибок), первый просто не фиксирует изменения.
- Вы пытаетесь убить процесс извне. Например, когда ваш супервизор перезапускается или связанный процесс умирает.
В этом случае вы также можете быть в центре чего-то, но Эрланг дает вам trap_exit
флаг. Это означает, что вместо смерти процесс получит сообщение, которое вы можете обработать. Это, в свою очередь, означает, что terminate
функция будет вызвана после того, как вы доберетесь до receive
блок. Таким образом, процесс завершит один кусок работы, и когда он будет готов к следующему, он вызовет terminate
и после этого умереть.
Таким образом, вы можете обойти выход с помощью trap_exit
, Вы также можете обойти trap_exit
отправка exit(Pid, kill)
, который завершает процесс, даже если он перехватывает выходы.
Обойтись невозможно exit(Pid, kill)
так что будьте осторожны с его использованием.