migmit: (Default)
[personal profile] migmit
Уже в нескольких местах рассказывал одну и ту же байку. Надо бы оформить постом, и потом только ссылку давать.

Итак. Года два-три назад писал я на Эрланге. И вот возник один баг: некий процесс, скажем, Игрек, через некоторое время после запуска вдруг падает. Причём, скотина, падает даже без каких-либо сообщений в логах. А так как занят он довольно важным делом — теряется куча информации. Соответственно, релиз пришлось откатить (то ещё удовольствие) и начать разбираться.

Как оказалось, падает Игрек только под нагрузкой, так что скормить ему какие-то простенькие входные данные и аккуратно отследить, где именно его скрючит, не представляется возможным. Добавленные во все мыслимые места логи показывают, что падает процесс, в общем-то, где попало. Точнее не совсем где попало, в некоей небольшой области, но не в строго определённом месте. Я поначалу грешил на оптимизатор (случалось сталкиваться с тем, что лог выведен, а предыдущая строчка таки не выполнилась из-за того, что процесс упал), но потом понял, что наш случай таки выходит за пределы бардака, который может устроить оптимизатор. А самое смешное, что, судя по логам git, ни сам Игрек, ни вообще что-либо в непосредственной близости от него, никто не трогал уже несколько месяцев. С чего он вдруг падать начал?

Что оказалось в итоге. Был некий другой процесс, скажем, Ипсилон. И он-то как раз занимался совершенно простенькой деятельностью; он принимал сообщение, смотрел, куда его сунуть, и отсылал дальше. Причём он дожидался ответа от конечного получателя ("ага, получили, спасибо"), но сам никакого ответа отправителю не возвращал. Реализован он был через gen_server, но реально никакого внутреннего состояния там не было; если точнее, внутреннее состояние всегда оставалось [].

Но какой-то гений, который его писал (я уже не помню, кто это был) слегка ошибся. Если кто не знает, то gen_server требует, чтобы в сервере была реализована функция handle_cast, которая, собственно, и решает, как именно следует реагировать на поступившее сообщение. Бизнес-логику реализует, если угодно. Так вот, эта функция должна была бы возвращать {noreply, []} (говоря тем самым "ответа не будет, новое состояние []"), но вместо этого возвращала {ok, []}. Нарушение типизации такое, ага.

gen_server такого ответа не понимает. Ну, тупой он, не знает, что ok — значит, типа, всё здорово, давай дальше в том же духе. Поэтому, по завершении handle_cast, он, в полном соответствии с идеологией Erlang "let it crash" (т.е., "гори оно огнём") падает. Но дальше, опять-таки в полном соответствии с упомянутой идеологией, в дело включается супервизор. Который видит, что Ипсилон упал — и перезапускает его. А так как состояния у Ипсилона нет — всё работает как и должно. Вместо того, чтобы сидеть и дожидаться нового сообщения, Ипсилон падает, стартует заново, и дальше сидит и ждёт нового сообщения. И так оно работало не то чтобы месяцами — годами.

И вот что изменилось: сам Ипсилон мы тоже не трогали — а вот в одном из конечных получателей кое-что таки подкрутили и пооптимизировали. В результате ответ Ипсилону стал приходить гораздо быстрее. И Ипсилон стал, в результате, работать быстрее. А так как его работа — это постоянные падения, то и падать он стал чаще. Если под нагрузкой, конечно; когда приходит одно сообщение в час, то он и падать будет раз в час.

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

Date: 2016-01-31 03:33 pm (UTC)
From: [identity profile] migmit.livejournal.com
В солюшене — штук тридцать проектов. Эти два оказались в одном проекте — их писали, имея в виду одну и ту же, довольно крупную, фичу. Ну и результат.

А диалайзер — особая головная боль. Я как-то для студентов нарисовал одну программку, строк на десять, где КАЖДАЯ строка содержала хотя бы одну ошибку типизации. И натравил на это диалайзер. Получил 1 (один) ворнинг. Причём неправильный. То, что программа вообще никакого смысла не имеет и работать не может, он не заметил. Добавить сюда ещё случаи, когда диалайзер даёт false positives (логично даёт, но от этого не легче), и пожалуйста — пользоваться им невозможно.

Date: 2016-01-31 03:40 pm (UTC)
develop7: (dero)
From: [personal profile] develop7
Я как-то для студентов нарисовал одну программку, строк на десять, где КАЖДАЯ строка содержала хотя бы одну ошибку типизации. И натравил на это диалайзер. Получил 1 (один) ворнинг. Причём неправильный.
интересно. продублируйте, пожалуйста, сюда.

Date: 2016-01-31 04:19 pm (UTC)
From: [identity profile] migmit.livejournal.com
Не думаю, чтобы оно у меня сохранилось. Это было года два назад, и я больше там не работаю.

Date: 2016-01-31 08:27 pm (UTC)
develop7: (dero)
From: [personal profile] develop7
ну эм, хоть что-нибудь?

Date: 2016-02-01 08:41 am (UTC)
From: [identity profile] dmitriid.livejournal.com
Если будет возможность вспомнить/восстановить, ОЧЕНЬ большая просьба выложить пример. Тогда можно будет отправить пример в рассылку эрланговскую. Думаю, авторы диалайзера будут только благодарны :)

Date: 2016-02-01 07:59 pm (UTC)
From: [identity profile] avnik.livejournal.com
Ну вот даже выбрасывая язык/уходя с проекта -- такие штуки надо репортить.
Улучшает собственную карму

Date: 2016-02-01 08:03 pm (UTC)
From: [identity profile] migmit.livejournal.com
Да мне лениво было искать, куда репортить. Не говоря уже о том, что Диалайзер и не должен ловить ВСЕ ошибки типизации, так что я понятия не имел, что из этого нормально, а что нет.

Date: 2016-02-03 01:31 am (UTC)
From: [identity profile] love5an.livejournal.com
Оффтоп конечно, но подумалось, давно же все это было, блин. Алерт, вот это все. Как-то даже взгрустнулось.

Date: 2016-02-03 11:18 am (UTC)
From: [identity profile] migmit.livejournal.com
Чего-чего, а тоски по алерту я не испытываю от слова "совсем". Паршивое местечко.