Перейти к основному содержимому

ADR 0209 — Engine переходит на Elixir 1.20.4 / OTP 29.1.1

Статус​

Accepted. 2026-10-02 (AT-398; решение владельца от 02.10, "subir o engine para OTP 29.1.x"). Меняет runtime, зафиксированный в ADR 0024 (решение 10: одна и та же версия Elixir в Dockerfiles и в CI), не редактируя его, — правило ЕДИНСТВЕННОЙ версии продолжает действовать, меняется сама версия.

Контекст​

С AT-361 Dockerfile.prod engine работает на Alpine 3.24.2 с OTP 27.3.4.18 (hexpm не публикует 27.1.2 на 3.24), тогда как dev и CI оставались на Elixir 1.17.3 / OTP 27.1.2 / Alpine 3.20.3. Сборка engine в CI начала обрываться примерно в 10% прогонов (0/57 до #821, 5/49 после) с:

sys_signal_stack.c:101:sys_sigaltstack(): Internal error

Измеренная причина: musl 1.2.6 из Alpine 3.24 отвергает альтернативный стек сигналов фиксированного размера (SIGSTKSZ = 8192), который запрашивает ERTS 27, на хостах с AMX (erlang/otp#11349). Исправление — определять размер через sysconf(_SC_MINSIGSTKSZ) (коммиты 3a94587176/fc35c2496c) — существует ТОЛЬКО начиная с OTP 29.1. Тот же дефект заставил бы ПРОДАКШЕН-engine умереть при загрузке на сервере с AMX: перемежающийся сбой CI — это лотерея машин.

Откат Alpine до 3.22 решил бы симптом и заморозил бы образ на линии, которая перестаёт получать исправления безопасности; это не было выбрано.

Решение​

  1. Engine работает на Elixir 1.20.4 / OTP 29.1.1 в dev, продакшене и CI. Образ — hexpm/elixir:1.20.4-erlang-29.1.1-alpine-3.24.2, закреплённый по digest ИНДЕКСА (sha256:ad851f40…, ADR 0159/0178), ОДИН И ТОТ ЖЕ в builder Dockerfile.prod и в Dockerfile для dev. Продакшен-runtime остаётся alpine:3.24.2 (musl builder совпадает с musl runtime). Elixir 1.20 — единственная линия с образом и сборкой hexpm для OTP 29.1.
  2. ELIXIR_VERSION/OTP_VERSION поднимаются вместе в трёх workflows, которые их объявляют (ci.yml, golden-set-rag.yml, golden-set-qa.yml), а mix.exs начинает требовать ~> 1.20.
  3. Job "Build, scan e smoke" печатает, есть ли у хоста AMX (grep -c amx_tile /proc/cpuinfo): зелёный на хосте с AMX — доказательство того, что дефект не вернулся, а не удача лотереи.
  4. Ни одна зависимость mix.lock не изменилась: mix deps.get + mix compile --warnings-as-errors проходят на новой версии. Проверщик типов Elixir 1.20 указал на мёртвую клаузулу в Engine.Agents.FilaDeMensagens.acordar/3 — сбой подъёма агента БРОСАЕТСЯ, а не возвращается как значение, — и она была исправлена с локализацией ошибки по агенту, а не заглушена.

Последствия​

  • Цена для dev: тома _build/deps engine были скомпилированы с OTP 27. Mix сам перекомпилирует то, что было собрано другой версией Elixir, поэтому достаточно docker compose up -d --build engine; если том упорно держит старый артефакт, docker volume rm для двух томов engine. Поскольку это автоматическая перекомпиляция, изменение НЕ является breaking для эксплуатирующего.
  • Тому, кто запускает engine вне Docker, нужен Elixir 1.20.4 / OTP 29.1.1 (mix format --check-formatted зависит от версии, ADR 0024, решение 10).
  • Dependabot docker: с OTP 29.1 + Alpine 3.24 сломанной пары больше нет, и ни одного ignore не добавлено. Он может предложить более новый тег hexpm/elixir OTP 29.1.x — все содержат исправление. Предложение, которое ОПУСКАЕТ до OTP < 29.1 при Alpine ≥ 3.24, вновь вносит дефект и должно быть отклонено при ревью.
  • Rollout в Kubernetes на мгновения смешивает узлы OTP 27 и 29: распределённый Erlang допускает пары с разницей в две старшие версии.