umbot
    Preparing search index...

    Полные результаты тестов производительности umbot

    Все тесты проводились на чистой установке без сетевых вызовов, внешних API или пользовательской логики.
    Измерялось только время выполнения внутренней логики фреймворка: от получения запроса до формирования объекта ответа.


    Ниже приведены результаты тестирования времени выполнения только внутренней логики фреймворка, исключая время выполнения action. Тесты проводились на системе с AMD Ryzen 5 5600G, 32 ГБ ОЗУ, SSD.

    Примечание: Время первичной загрузки новых изображений или аудиофайлов (когда token для файла ещё не кэширован в БД) может значительно превышать 1 секунду и выделено отдельно. После первой загрузки и кэширования, последующие обращения к тем же файлам выполняются быстро.

    Особое внимание уделено оптимизации работы с регулярными выражениями (RegExp). При использовании isPattern: true, umbot кэширует скомпилированные RegExp объекты. Это означает, что при первом вызове run() с командами, использующими новые паттерны, происходит компиляция RegExp, что занимает больше времени. При последующих вызовах с теми же паттернами, скомпилированные RegExp берутся из кэша, что значительно ускоряет выполнение. Также в фреймворке предусмотрена группировка регулярных выражений из разных команд. То есть когда задано множество команд с регулярными выражениями, эти регулярные выражения объединяются в группы, для уменьшения количества обращений.

    Стенд benchmark/comparison/ сравнивает umbot с реальными фреймворками конкурентов по платформам. У стенда собственный benchmark/comparison/package.json (зависимости-конкуренты не попадают в package.json репозитория). Каждый стенд — отдельный файл: сценарии, lockstep, метрики и печать общие (runner.js), файл платформы задаёт вход и подключает конкурентов. Запуск:

    npm i --prefix benchmark/comparison
    npm run compare # Telegram: umbot vs grammy, telegraf
    npm run compare:alisa # Alisa: umbot vs yandex-dialogs-sdk
    npm run compare:vk # VK: umbot vs vk-io (+ @vk-io/hear)
    npm run compare:viber # Viber: umbot vs viber-bot
    npm run compare:max # MAX: umbot vs @maxhub/max-bot-api

    Файлы стендов устроены одинаково (telegram.js, alisa.js, vk.js, viber.js, max.js): makeUpdate — апдейт платформы, umbot — адаптер и botType, competitors() — офлайн-путь каждого конкурента (обработка через штатный handleUpdate/handleRequest/handleWebhookUpdate, без сети). Добавление нового конкурента: пакет — в dependencies benchmark/comparison/package.json, реализация — в competitors() файла платформы по образцу существующих.

    Дополнительно в benchmark/comparison/:

    • Стресс-стенд stress.js (запуск: npm run stress:compare:vk и т.п., или node stress.js <файл> [сек] [окно]) — поведение под непрерывным потоком: окно 200 запросов in-flight, 30 с, трафик-микс (точное/частичное/регулярка/fallback = 40/25/25/10), ротация 1000 user_id, 1000 команд. Метрики: агрегатный RPS под потоком (не путать с 1000/p50 тепличного стенда — другой режим), p50/p95/p99, доля времени в GC, тренд пола кучи (пила мусора — норма, рост пола — проблема), retained-дельта после финального GC (утечка). Каждый участник — в изолированном дочернем процессе: падение одного по heap limit роняет только его строку.
    • Cold-start и IQR — встроены в основной стенд: время первых 200 запросов после регистрации без прогрева (прода-метрика serverless: латентность первого запроса после подъёма инстанса; печатается отдельным блоком — числа несопоставимы со steady-state) и межквартильный размах p75−p25 (ширина ядра распределения; p95 дёргается от единичных выбросов ОС, IQR устойчивее).
    • Регрессионный baseline baseline.js для CI night-job: npm run baseline:update — записать p50 umbot на маркерном сценарии «50 команд, точное совпадение» всех пяти стендов; npm run baseline:check — свериться (допуск +15% JIT-шума; exit 1 при регрессии). Ловит «кто-то занёс тяжёлый RegExp-компайл в горячий путь» автоматикой, а не ручным прогоном. Baseline-файл создаётся на той же машине, где гоняется check.

    Честность стенда (едина для всех платформ):

    • Один вход для всех: одинаковый апдейт платформы (структура байт в байт). umbot подключён штатным адаптером платформы; конкуренты обрабатывают его своим штатным офлайн-путём (handleUpdate у grammy/telegraf/max-bot-api, handleRequest у yandex-dialogs-sdk, handleWebhookUpdate у vk-io, _handleEventReceived у viber-bot). botInfo конкурентам задаётся явно (документированная опция/свойство), иначе их handleUpdate ходит за getMe в сеть.
    • Сеть исключена у всех: команды umbot ставят ctx.skipAutoReply = true (без него его getContent ушёл бы в API платформы — мерился бы интернет); у конкурентов ctx.reply/ctx.send не вызывается. VkAdapter в стенде работает с vk_load_user_info: false — иначе адаптер по умолчанию ходит в VK API за именем пользователя на каждое сообщение.
    • Семантика выровнена: подстрочный матч у всех — конкурентам команды заданы как hears(new RegExp(...))/аналог (единая обёртка asRegExp в runner.js; до выравнивания их hears(строка) матчит только точное совпадение — проверено по исходникам и поведенческим тестом на каждой библиотеке: grammy — txt === t, telegraf и max-bot-api — new RegExp('^…$'), @vk-io/hear — text === condition, viber-bot строковых триггеров не имеет). RegExp-вариант — их честная цена той же семантики, что у umbot-слота.
    • Lockstep-чередование раундов (интерливинг: в каждом раунде все участники идут по очереди — тепловой дрейф CPU распределяется на всех поровну), медиана из 10 раундов; латентность каждого запроса замеряется отдельно (отсюда p95).
    • Пауза после регистрации команд (100 мс у vk-io/viber/max/alisa, 50 мс в каркасе) — у всех участников: регистрация не мгновенна (umbot пересобирает снимок команд и компилирует RegExp, конкуренты recompose-ят/достраивают middleware-цепочки) — хвосты инициализации не должны попадать в замер.
    • Прогрев до плато (методика v4): до измеряемой серии каждый участник гоняется циклами по 500 запросов, пока медиана цикла перестаёт улучшаться (до 20 циклов = 10 000 запросов). Причина: кривая tier-up/inline-кэшей V8 сходит на плато только через тысячи вызовов. С фиксированным прогревом 2×500 запросов стенд ловил участников на крутом участке кривой: у «толстого» фреймворка (umbot: контроллер на 30 полей, ленивые компоненты, больше полиморфных call-site'ов) выход на плато медленнее, и он выглядел медленнее собственного steady-state. Прогрев до плато убирает этот перекос в обе стороны, но не отменяет реальную разницу: на малых базах лёгкие роутеры (vk-io, max-bot-api) остаются вровень или чуть быстрее — см. таблицы ниже.
    • Латентности и память — раздельные фазы: вся фаза латентностей идёт без единого вызова GC; фаза памяти (с forceGC) запускается только после её завершения. Пока фаза памяти стояла в том же раунде, каждый следующий раунд наследовал только что скомпактированную кучу: полный GC — это compaction, после которого V8 восстанавливает inline-кэши несколько запросов (полиморфный путь — дольше монолитного), и pooled p50 взлетал у обеих сторон в ~1.5 раза (матрица методик, VK, 6 команд: с forceGC перед замером 3.0/2.2 мкс; фаза памяти в том же раунде 3.4/3.3; без GC вовсе 2.3/2.3 — паритет; steady-эталон 1.7/1.2). GC в замере измерял чувствительность к compaction, а не стоимость маршрутизации.
    • Победа — только при отрыве >5% и >0.3 мкс: при меньшей разнице строки помечаются «паритет» (шум прогона), а не «лучший» у обоих.

    Результаты ниже — прогон от сентября 2026 (методика v4). Окружение: AMD Ryzen 5 5600G (6 ядер / 12 потоков), 32 ГБ ОЗУ, Windows 10, Node.js 24.15.0, без re2. Версии конкурентов зафиксированы в benchmark/comparison/package-lock.json: grammy 1.46.0, telegraf 4.16.3, yandex-dialogs-sdk 2.3.0, vk-io 4.10.1 (+ @vk-io/hear 1.1.1), viber-bot 1.0.18, @maxhub/max-bot-api 0.3.0.

    • Только стоимость роутинга внутри процесса. Без HTTP-сервера, без сети, без БД и без бизнес-логики: апдейт передаётся фреймворку напрямую, ответ никуда не отправляется. В живом боте время ответа пользователю определяет сеть (десятки–сотни миллисекунд), а не эти микросекунды. Бенчмарк показывает, сколько CPU уходит на один апдейт — то есть сколько апдейтов выдержит одно ядро и сколько мусора получит GC.
    • Колонка RPS в тепличных таблицах — это 1000 / p50 для одного ядра, теоретический потолок роутинга, а не пропускная способность сервера. «666 667 RPS» означает «роутинг занимает 1,5 мкс», а не «сервер обслужит 666 тысяч запросов в секунду».
    • Конкуренты подключены так, как их обычно используют: одна команда — один обработчик (bot.hears(...), аналоги у остальных). В grammY/telegraf каждый такой обработчик — отдельный слой middleware, апдейт проходит слои по очереди. Поэтому их стоимость растёт линейно с числом команд, а у umbot точное совпадение ищется в хэш-таблице за константу. Если в grammY написать один общий обработчик со своим Map, разрыв на больших базах пропадёт — стенд сравнивает встроенный роутинг, а не «лучший возможный код на каждом фреймворке».
    • umbot делает больше работы на апдейт: создаёт контроллер, NLU, состояние, шаги. Конкуренты в стенде — только маршрутизация.
    • 500–1000 команд — редкость. Типичный бот — 10–50 команд. Там разница на Telegram — 2–9 раз в микросекундах, а с vk-io и max-bot-api — паритет (см. таблицы).
    • На малых базах результат плавает от прогона к прогону в пределах 0,1–0,3 мкс: один и тот же сценарий может выйти «паритетом» или «победой» любой стороны. Правило стенда: победа — только при отрыве больше 5% И больше 0,3 мкс, иначе «паритет».
    npm run build
    npm i --prefix benchmark/comparison
    npm run compare # Telegram (grammy, telegraf); ещё: compare:alisa / compare:vk / compare:viber / compare:max
    npm run stress:compare # стресс под потоком; ещё: stress:compare:alisa / :vk / :viber / :max
    node benchmark/comparison/stress.js telegram.js 10 2000 # окно 2000 одновременных запросов

    Абсолютные цифры на другой машине будут другими; соотношения и форма кривой («растёт ли время с числом команд») должны совпасть. Если у вас выходит иначе — это повод открыть issue с выводом стенда.

    Сценарий (найденная команда — в середине списка) Реализация Время p50, мкс p95, мкс RPS (1000/p50) Память, КБ/запр
    6 команд, точное совпадение umbot 1.4 2.2 714 286 4.9
    grammy 3.1 6.7 322 581 13.2
    telegraf 3.8 8.5 263 158 15.9
    6 команд, регулярка umbot 1.5 2.8 666 667 4.7
    grammy 2.7 5.2 370 370 13.2
    telegraf 3.5 6.9 285 714 15.8
    50 команд, точное совпадение umbot 1.5 3.4 666 667 4.7
    grammy 14.1 26.7 70 922 76.3
    telegraf 17.6 29.7 56 818 97.4
    50 команд, частичное совпадение umbot 2.7 4.9 370 370 4.7
    grammy 14.0 26.0 71 429 76.4
    telegraf 17.9 30.2 55 866 97.3
    50 команд, регулярка umbot 2.9 5.6 344 828 4.7
    grammy 14.2 25.4 70 423 76.4
    telegraf 18.5 33.7 54 054 97.2
    50 команд, fallback umbot 3.8 7.3 263 158 4.7
    grammy 23.6 39.2 42 373 115.8
    telegraf 29.7 52.4 33 670 27.5
    500 команд, точное совпадение umbot 1.5 2.3 666 667 4.7
    grammy 137.6 225.2 7 267 40.5
    telegraf 170.6 279.1 5 862 127.7
    500 команд, частичное совпадение umbot 10.9 21.5 91 743 4.8
    grammy 142.2 235.5 7 032 39.2
    telegraf 169.1 278.7 5 914 127.7
    500 команд, регулярка umbot 35.3 48.7 28 329 4.8
    grammy 249.0 429.2 4 016 39.2
    telegraf 300.3 665.2 3 330 125.9
    1000 команд, точное совпадение umbot 2.1 4.2 476 190 4.7
    grammy 450.6 767.7 2 219 73.9
    telegraf 505.9 800.7 1 977 118.5
    1000 команд, регулярка umbot 37.8 68.8 26 455 7.6
    grammy 353.4 841.4 2 830 73.9
    telegraf 462.8 917.6 2 161 118.5
    1000 команд, частичное совпадение umbot 31.4 62.3 31 847 4.9
    grammy 334.1 668.5 2 993 73.9
    telegraf 423.0 831.6 2 364 118.5
    1000 команд, fallback (неизвестная фраза) umbot 45.6 91.5 21 930 4.8
    grammy 587.4 1532.9 1 702 30.1
    telegraf 820.6 1927.8 1 219 100.6

    Как читать (включая неудобное):

    • umbot быстрее в 13 из 13 сценариев. На 6 командах — примерно в 2 раза (1.4 против 3.1 мкс), на 50 — в 5–9 раз, на 500–1000 — на один-два порядка. Рост у конкурентов — это цена цепочки middleware (см. «Что именно меряется»).
    • Регулярки на больших базах у umbot тоже не бесплатны: 35–38 мкс при 500–1000 командах — регулярки объединены в группы, но проверяются всё равно. Точное совпадение — 1.5–2.1 мкс независимо от числа команд.
    • Память: umbot 4.7–7.6 КБ на апдейт против 13.2–127.7 КБ у grammy и telegraf — в 2.7–27 раз меньше работы для GC на Telegram. На других платформах картина другая (см. ниже).
    • Утечек нет ни у кого.
    • Окно 2000 одновременных запросов (node benchmark/comparison/stress.js telegram.js 10 2000, 1000 команд, 10 с): umbot — 74 031 RPS, p99 33 мс, куча 15 МБ; grammy — 518 RPS, p99 6.6 с, куча ~1.9 ГБ; telegraf — 292 RPS, p99 12 с, куча ~3.1 ГБ (близко к лимиту кучи Node по умолчанию ~4 ГБ).

    Те же сценарии и правила (методика v4). Ключевые числа — время p50 на апдейт; полный вывод печатает каждый стенд:

    Конкурент Счёт umbot 6 команд, точное 1000 команд, точное 1000 команд, регулярка Память на апдейт
    yandex-dialogs-sdk 13 побед из 13 1.9 против 4.5 мкс 1.6 против 142.2 мкс 35.6 против 222.8 umbot меньше везде (4.1–7.6 против 7.5–112)
    vk-io 7 побед, 5 паритетов, 1 поражение 1.5 против 1.2 мкс 1.2 против 24.8 мкс 53.7 против 72.5 6 команд: vk-io меньше (3.3 против 5.2); с 50 команд umbot меньше (до 100 КБ у vk-io)
    viber-bot 13 побед из 13 1.5 против 1.9 мкс 3.5 против 210.9 мкс 66.5 против 259.3 до 50 команд viber-bot меньше (1.5–3.8 против 4.6–4.9); с 500 команд umbot меньше
    max-bot-api 11 побед, 2 паритета 1.4 против 1.3 мкс 1.2 против 131.9 мкс 36.3 против 153.3 umbot меньше везде (4.4–7.2 против 6.3–117)

    Как читать (включая неудобное):

    • VK, малые боты — vk-io не хуже, а местами быстрее. «6 команд, точное» vk-io выигрывает (1.2 против 1.5 мкс), ещё 5 сценариев — паритет («6 регулярка», «50 частичное/регулярка/fallback», «1000 частичное»). vk-io — лёгкий роутер без контроллера, NLU и состояния; umbot платит за свой конвейер. Разница в десятые доли микросекунды — пользователь её не увидит. Выигрыш umbot у vk-io появляется на точном совпадении при 50+ командах (хэш-таблица) и на регулярках при 500+.
    • MAX, 6 команд — паритет (1.4 против 1.3 мкс). С 50 команд umbot впереди во всех сценариях.
    • Память — не везде в пользу umbot. Контроллер umbot стоит ~5 КБ на апдейт даже на маленьком боте: viber-bot (до 50 команд) и vk-io (6 команд) выделяют меньше. С ростом числа команд конкуренты выделяют больше (у vk-io и max-bot-api — до ~100–117 КБ на апдейт).
    • Алиса: umbot впереди во всех 13 сценариях. У yandex-dialogs-sdk роутинг — Promise.all по всем командам на каждый запрос ради подбора «похожих» фраз (проверено по исходникам), отсюда рост с числом команд. SDK не обновлялся с 2022 года.
    • viber-bot и yandex-dialogs-sdk не обновлялись с 2022 года, но это главные (и почти единственные) фреймворки своих платформ в npm. Для Маруси и SmartApp сторонних фреймворков нет — сравнивать не с кем.
    • Результаты малых баз плавают от прогона к прогону (см. «Что именно меряется»): в прошлых прогонах VK выходил без поражений, а Viber — с одним поражением на «6 команд, регулярка».

    Стресс-стенд (stress.js) меряет не латентность отдельного запроса, а поведение под потоком: окно 200 запросов in-flight, 30 с, микс 40/25/25/10 (точное/частичное/регулярка/fallback), 1000 команд (намеренно тяжёлый сценарий), ротация 1000 разных user_id. Каждый участник — в отдельном процессе:

    Стенд Участник Запросов RPS p50 p99 GC, % времени Утечка
    VK umbot 2 263 000 75 420 2.4 мс 4.6 мс 0.3 нет (0.10*)
    vk-io 960 706 31 985 3.2 мс 7.1 мс 2.7 нет
    Telegram umbot 2 355 000 78 487 2.4 мс 4.3 мс 0.3 нет (0.12*)
    grammy 11 136 370 515 мс 905 мс 64.0 нет
    telegraf 7 664 253 747 мс 1 467 мс 66.0 нет
    Alisa umbot 2 076 800 69 190 2.6 мс 5.1 мс 0.3 нет (0.17*)
    dialogs-sdk 82 112 2 734 67 мс 105 мс 16.3 нет
    Viber umbot 2 210 400 73 654 2.5 мс 4.6 мс 0.3 нет (0.13*)
    viber-bot 200 986 6 698 15 мс 31 мс 0.3 нет
    MAX umbot 2 259 800 75 290 2.5 мс 4.5 мс 0.3 нет (0.11*)
    max-bot-api 22 285 742 253 мс 373 мс 65.6 нет

    * КБ на 1000 запросов: постоянный прогретый набор (JIT, кэш регулярок групп) — суммарно ~260 КБ и за 5 с, и за 20 с потока, от длительности не зависит.

    Исправление методики (3.1.0). В прежней версии стенда retained-память мерилась, пока массив задержек самого воркера (8 байт на запрос) был ещё жив. «Утечка» получалась пропорциональной числу запросов и штрафовала самого быстрого участника: у umbot выходило 8–10 КБ/1000 запросов, у telegraf (177 КБ/1000) и max-bot-api (57 КБ/1000) — тоже артефакт. Квантили теперь считаются до замера, массив освобождается; после исправления утечек нет ни у одного участника. Цифры в таблице — прогон после исправления.

    Как читать (включая неудобное):

    • Это худший для конкурентов режим, и он выбран сознательно: 1000 команд и постоянный поток. Разрыв в стрессе (2.4–310×) больше, чем в тепличных таблицах, потому что добавляется сборка мусора: цепочка из 1000 async-обработчиков × 200 одновременных апдейтов создаёт сотни тысяч живых промисов и замыканий, и grammy/telegraf/max-bot-api тратят до 66% времени на GC. У umbot точное совпадение не создаёт мусора на каждый обработчик, поэтому GC — 0.3%.
    • На ботах с 10–50 командами такого разрыва нет — см. тепличные таблицы: там разница в единицы микросекунд, а с vk-io и max-bot-api — паритет.
    • vk-io — самый сильный конкурент под потоком (2.4×), viber-bot держится ровно (GC 0.3%), но медленнее в 11 раз.
    • Агрегатный RPS ≠ 1000/p50 тепличного стенда: под потоком латентность растёт у всех из-за очереди.
    • Без fallback-команды * базовый контроллер umbot на промахе отвечает пользователю, то есть делает сетевой вызов в API платформы. Стенд регистрирует * с skipAutoReply, чтобы мерить роутинг, а не интернет. В проде промах без обработчика — это реальный запрос к платформе.

    Время первых 200 запросов после регистрации команд, без прогрева (важно для Cloud Functions: первый запрос после подъёма инстанса). Холодный JIT платит первый запрос в десятки раз дороже плато; участники стартуют в одинаковых условиях:

    Платформа Сценарий umbot: 1-й / ср. 200, мкс Конкурент: 1-й / ср. 200, мкс
    Telegram 6 команд, точное 1 364 / 14.0 grammy 688 / 14.8
    Telegram 1000 команд, точное 193 / 7.3 grammy 1 806 / 422.9
    Alisa 6 команд, точное 1 540 / 16.4 dialogs-sdk 905 / 15.2
    VK 6 команд, точное 1 659 / 19.9 vk-io 634 / 7.5
    VK 1000 команд, точное 124 / 8.6 vk-io 523 / 59.5
    Viber 6 команд, точное 1 277 / 14.0 viber-bot 581 / 7.5
    MAX 6 команд, точное 1 326 / 13.3 max-bot-api 433 / 11.7

    Как читать: на малых базах первый запрос у umbot в 1.7–3 раза медленнее, чем у всех конкурентов (1.3–1.7 мс против 0.4–0.9 мс) — у umbot больше кода, который V8 компилирует при первом вызове. Для serverless это ~1 мс на холодный старт инстанса. С ростом числа команд umbot и в холодном старте впереди: точное совпадение не требует прогрева.

    Конкурент Тепличный стенд (13 сценариев) Стресс, 1000 команд (RPS) Память на апдейт
    grammy (Telegram) umbot быстрее во всех 13 78 487 против 370 (212×) umbot меньше везде (в 2.7–25 раз)
    telegraf umbot быстрее во всех 13 78 487 против 253 (310×) umbot меньше везде (в 3.2–27 раз)
    yandex-dialogs-sdk umbot быстрее во всех 13 69 190 против 2 734 (25×) umbot меньше везде
    vk-io 7 побед, 5 паритетов, 1 поражение 75 420 против 31 985 (2.4×) на 6 командах vk-io меньше, дальше umbot
    viber-bot umbot быстрее во всех 13 73 654 против 6 698 (11×) до 50 команд viber-bot меньше, дальше umbot
    max-bot-api 11 побед, 2 паритета (6 команд) 75 290 против 742 (101×) umbot меньше везде

    Где umbot уступает или идёт вровень:

    • vk-io на малых ботах: быстрее на «6 команд, точное» (0.3 мкс), паритет ещё в 5 сценариях.
    • max-bot-api на 6 командах — паритет.
    • Память на малых ботах: vk-io (6 команд) и viber-bot (до 50 команд) выделяют меньше.
    • Cold-start на малых базах — медленнее всех конкурентов (на ~0.5–1 мс).

    Где umbot стабильно лучше:

    • Рост числа команд: точное совпадение — 1.2–3.5 мкс при любом числе команд против 24.8–450 мкс у конкурентов при 1000 командах.
    • Поведение под потоком на больших базах: 2.4–310× по пропускной способности, GC 0.3%.
    • Утечки — нет ни у кого, у umbot retained — постоянный прогретый набор ~260 КБ.

    Практический вывод: на малых ботах (до ~50 команд) решает не быстродействие — разница в долях микросекунды не видна на фоне сетевого круга платформы в 50–300 мс, — а функциональность (мультиплатформенность, шаги, NLU, state). На ботах с сотнями команд и высоким потоком у umbot кратный запас по CPU и памяти.

    Честная оценка границ инструмента (а не только его сильных сторон):

    umbot создан для:

    • навыков и ботов, управляемых текстом: команды, фразы, fallback-реакции, многошаговые диалоги (addStep), формы-опросники (addForm);
    • мультиплатформенности: одна бизнес-логика на 7 платформ (Алиса, Маруся, SmartApp, Telegram, VK, MAX, Viber) — включая голосовые с TTS, кнопками, карточками и NLU;
    • продуктов, где важна предсказуемая ресурсность: постоянное потребление памяти, отсутствие утечек (48-часовой стресс-тест), в 2.7–27 раз меньше мусора на запрос, чем у Telegram-фреймворков grammy и telegraf;
    • высоконагруженных навыков: health-check, метрики, rate-limiting middleware, ReDoS-защита из коробки.

    Сценарии, где потребуется дополнительная логика на вашей стороне:

    • Не-текстовые апдейты: декларативный роутинг по типу события есть — bot.addEvent('photo' | 'voice' | 'callback' | 'inline' | ...), 17 универсальных типов, адаптеры платформ объявляют поддержку через supportedEvents (валидация и предупреждения при подключении). Доп. код потребуется только там, где нужна глубокая платформенная специфика события (например, бизнес-логика по полям, которые нет смысла унифицировать) — читайте controller.eventType, controller.payload и requestObject прямо в хендлере события;
    • Telegram-only-специфика глубокого уровня: обвязка «одной строкой» для частых сценариев есть — событийный роутинг bot.addEvent(...) + кросс-платформенный API-фасад ctx.api?.sendPhoto/sendDocument/ sendAudio/sendVideo/answerCallback (с матрицей поддержки по платформам и can(method), см. api-reference.md). Однако полный охват Bot API (web-app, payments, games, бизнес-режимы и прочий длинный хвост методов) остаётся за TelegramRequest — вызовы собираются вручную через API-клиент;
    • Экстремальные базы команд (>10 000 статических строковых команд): линейный скан при промахе честно задокументирован выше — для таких объёмов фреймворк сам рекомендует параметризованные команды/NLU/внешний API (см. bench-вывод), либо включите re2 для регулярных выражений.

    Ключевая мысль: umbot — не «универсальный фреймворк на все случаи», а инструмент для сценария «диалоговый бот/навык на многих платформах с предсказуемыми ресурсами». Если ваш продукт — диалоги, команды и шаги, вы получаете всё из коробки и производительность выше конкурентов. Если ваш продукт — обработка медиа-потоков или тонкая Telegram-специфика, взвесьте: дополнительный код на umbot против отказа от 6 других платформ и ресурсной эффективности.

    Бенчмарки bench и stress перед запуском проверяют, хватит ли памяти. Проверка учитывает три реальных ограничения: лимит heap V8 (--max-old-space-size или ~4 ГБ по умолчанию — даже при 16 ГБ RAM Node не аллоцирует больше), cgroup-лимит (docker/k8s) и физическую память с учётом page cache (ядро сбрасывает кэш при нехватке — os.freemem() на unix занижает доступное, из-за чего тест ложно отказывался в запуске). Оценка потребления основана на фактических замерах: ~466 Б на строковую команду, ~0.8 КБ на isPattern-команду, ~1.6 КБ с учётом фрагментации V8 кучи при экстремальных количествах.

    Команда Описание
    npm run bench Время обработки команд с разной сложностью regex (9 уровней от 50 до 1 000 000 команд)
    npm run stress Стресс-тест: полная нагрузка (1003 команды, параллельные запросы, burst-тесты, максимальный RPS за 15 сек)
    npm run stress:lite Облегчённый стресс-тест (8 команд вместо 1003). Подходит для быстрой проверки на слабом оборудовании
    npm run stress:long Долгосрочный тест на 48 часов. Проверяет утечки памяти и стабильность производительности
    npm run comparison Честное сравнение umbot против «чистой» реализации роутера (lockstep, медианы; свой роутер — через UM_COMPARISON_ROUTER)
    npm run compare Сравнение с реальными фреймворками: compare — Telegram (grammy, telegraf); compare:alisa — Alisa (yandex-dialogs-sdk); compare:vk — VK (vk-io); compare:viber — Viber (viber-bot); compare:max — MAX (max-bot-api). Одинаковый вход, p50/p95/IQR/RPS/память + cold-start (см. выше)
    npm run stress:compare:* Стресс-стенд против конкурентов: stress:compare — Telegram; stress:compare:alisa/vk/viber/max — другие платформы. 30 с непрерывного потока (окно 200 in-flight, микс 40/25/25/10, 1000 команд, 1000 user_id), агрегатный RPS, доля GC, тренд кучи, retained-утечка. Каждый участник в изолированном процессе
    npm run baseline:update / baseline:check Регрессионный контроль для CI night-job: p50 umbot на маркерном сценарии всех 5 стендов против baseline.json (допуск +15%); check возвращает exit 1 при регрессии