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-bot, max-bot-api и yandex-dialogs-sdk (они recompose-ят/достраивают middleware-цепочки асинхронно). umbot паузы не получает (delay у его участника не задан): отложенная сборка индексов поиска в синхронном цикле стенда не успевает сработать, и первые запросы идут обычным перебором, пока план не соберётся на пути запроса (после 64 поисков). Этот хвост попадает в cold-start umbot и в начало прогрева — не в пользу umbot.
    • Прогрев до плато (методика 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 мкс: при меньшей разнице строки помечаются «паритет» (шум прогона), а не «лучший» у обоих.

    Результаты ниже — прогон umbot 3.1.4 от сентября 2026 (методика v4). Окружение: AMD Ryzen 5 5600G (6 ядер / 12 потоков), 32 ГБ ОЗУ, Windows 10, Node.js 24.21.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 для одного ядра, теоретический потолок роутинга, а не пропускная способность сервера. «1 000 000 RPS» означает «роутинг занимает 1 мкс», а не «сервер обслужит миллион запросов в секунду».
    • Конкуренты подключены так, как их обычно используют: одна команда — один обработчик (bot.hears(...), аналоги у остальных). В grammY/telegraf каждый такой обработчик — отдельный слой middleware, апдейт проходит слои по очереди. Поэтому их стоимость растёт линейно с числом команд. У umbot точное совпадение ищется в хэш-таблице, подстрока — индексом подстрок, а регулярка запускается, только если в тексте есть её обязательная часть: время почти не зависит от числа команд. Если в grammY написать один общий обработчик со своим Map, разрыв на точных совпадениях пропадёт — стенд сравнивает встроенный роутинг, а не «лучший возможный код на каждом фреймворке».
    • umbot делает больше работы на апдейт: создаёт контроллер, NLU, состояние, шаги. Конкуренты в стенде — только маршрутизация.
    • 500–1000 команд — редкость. Типичный бот — 10–50 команд. Там разница на Telegram — в 2–14 раз, с vk-io — паритет на 6 командах и победа umbot с 50 (см. таблицы).
    • На малых базах результат плавает от прогона к прогону в пределах 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 0.9 1.8 1 111 111 2.2
    grammy 3.0 7.5 333 333 13.2
    telegraf 3.9 5.8 256 410 15.9
    6 команд, регулярка umbot 1.1 2.9 909 091 2.2
    grammy 3.1 5.3 322 581 13.2
    telegraf 3.8 5.2 263 158 15.7
    50 команд, точное совпадение umbot 1.1 2.2 909 091 2.2
    grammy 14.5 25.2 68 966 73.4
    telegraf 18.8 30.1 53 191 97.2
    50 команд, частичное совпадение umbot 1.4 3.3 714 286 2.3
    grammy 14.7 22.9 68 027 73.5
    telegraf 18.9 32.7 52 910 97.2
    50 команд, регулярка umbot 1.5 3.8 666 667 2.3
    grammy 14.5 23.4 68 966 73.5
    telegraf 19.5 30.9 51 282 97.2
    50 команд, fallback umbot 1.7 3.3 588 235 2.2
    grammy 24.1 38.0 41 494 115.7
    telegraf 31.0 48.7 32 258 27.4
    500 команд, точное совпадение umbot 0.9 1.5 1 111 111 2.2
    grammy 139.7 226.9 7 158 40.6
    telegraf 180.7 265.2 5 534 126.0
    500 команд, частичное совпадение umbot 1.6 3.1 625 000 2.3
    grammy 141.6 204.8 7 062 39.2
    telegraf 177.2 257.6 5 643 126.0
    500 команд, регулярка umbot 1.5 2.3 666 667 2.3
    grammy 160.5 265.9 6 231 39.2
    telegraf 195.1 342.5 5 126 126.0
    1000 команд, точное совпадение umbot 1.0 2.0 1 000 000 2.2
    grammy 301.0 567.0 3 322 73.9
    telegraf 375.8 691.4 2 661 118.6
    1000 команд, регулярка umbot 3.5 5.7 285 714 5.0
    grammy 354.4 855.9 2 822 73.9
    telegraf 433.7 975.9 2 306 118.6
    1000 команд, частичное совпадение umbot 1.5 3.9 666 667 2.3
    grammy 320.2 595.8 3 123 73.9
    telegraf 442.5 1061.7 2 260 118.6
    1000 команд, fallback umbot 1.9 7.6 526 316 2.2
    grammy 611.2 1823.1 1 636 30.2
    telegraf 762.9 1722.0 1 311 100.7

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

    • umbot быстрее в 13 из 13 сценариев. На 6 командах — в 3 раза (0.9 против 3.0 мкс), на 50 — в 10–14 раз, на 500–1000 — на два порядка. Рост у конкурентов — это цена цепочки middleware (см. «Что именно меряется»).
    • Время umbot почти не зависит от числа команд: 0.9–1.9 мкс на любом сценарии со строковыми командами, от 6 до 1000. Регулярки на 1000 командах — 3.5 мкс: регулярка запускается, только если в тексте есть её обязательная часть, но часть групп регулярок всё равно проверяется.
    • Память: umbot 2.2–5.0 КБ на апдейт против 13.2–126 КБ у grammy и telegraf — в 6–57 раз меньше работы для GC на Telegram.
    • Утечек нет ни у кого.
    • Окно 2000 одновременных запросов (node benchmark/comparison/stress.js telegram.js 10 2000, 1000 команд, 10 с): umbot — 598 272 RPS, p99 3.8 мс, куча 18 МБ; grammy — 422 RPS, p99 8.0 с, куча ~1.2 ГБ; telegraf — 239 RPS, p99 14.7 с, куча ~3.2 ГБ (близко к лимиту кучи Node по умолчанию ~4 ГБ).

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

    Конкурент Счёт umbot 6 команд, точное 1000 команд, точное 1000 команд, регулярка Память на апдейт
    yandex-dialogs-sdk 13 побед из 13 1.6 против 3.0 мкс 1.3 против 148.1 мкс 4.2 против 223.2 umbot меньше везде (3.3–6.3 против 7.5–112)
    vk-io 11 побед, 2 паритета 1.0 против 1.2 мкс 0.8 против 26.1 мкс 3.5 против 52.5 umbot меньше везде (2.1–4.8 против 3.3–100)
    viber-bot 13 побед из 13 1.9 против 3.7 мкс 2.1 против 231.4 мкс 6.2 против 269.6 6 команд: viber-bot меньше (1.5–1.6 против 2.1); с 50 команд umbot меньше
    max-bot-api 12 побед, 1 паритет 1.4 против 1.5 мкс 1.3 против 207.3 мкс 5.2 против 226.2 umbot меньше везде (2.2–4.8 против 6.3–117)

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

    • Поражений нет ни на одной платформе. Паритеты — только на 6 командах: VK «точное» и «регулярка» (1.0 против 1.2 и 1.2 против 1.5 мкс — umbot быстрее, но отрыв меньше порога стенда 0.3 мкс) и MAX «точное» (1.4 против 1.5 мкс). vk-io и max-bot-api — лёгкие роутеры без контроллера, NLU и состояния; umbot при этом делает больше работы на апдейт.
    • Время выхода на плато JIT. Горячий путь umbot длиннее, и V8 оптимизирует его позже: при прогреве меньше ~20 000 запросов на 6 командах umbot может быть на 0.1–0.2 мкс медленнее vk-io и max-bot-api, после — быстрее (например, «6 команд, регулярка» на VK: 0.67 против 0.94 мкс в долгом прогоне). Стенд прогревает до плато, но плато V8 не всегда совпадает с плато по медиане.
    • Память — не везде в пользу umbot. На 6 командах viber-bot выделяет 1.5 КБ на апдейт против 2.1 КБ у umbot: umbot создаёт контроллер на каждый запрос (~0.5 КБ) и проходит конвейер с async-обработкой (~1 КБ), viber-bot контекста запроса не создаёт. С 50 команд umbot выделяет меньше всех.
    • Алиса: umbot впереди во всех 13 сценариях. У yandex-dialogs-sdk роутинг — Promise.all по всем командам на каждый запрос ради подбора «похожих» фраз (проверено по исходникам), отсюда рост с числом команд. SDK не обновлялся с 2022 года.
    • viber-bot и yandex-dialogs-sdk не обновлялись с 2022 года, но это главные (и почти единственные) фреймворки своих платформ в npm. Для Маруси и SmartApp сторонних фреймворков нет — сравнивать не с кем.
    • Результаты малых баз плавают от прогона к прогону в пределах 0.1–0.3 мкс (см. «Что именно меряется»): паритет на 6 командах может выйти и победой umbot.

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

    Стенд Участник Запросов RPS p50 p99 GC, % времени Утечка
    VK umbot 21 473 753 715 481 133 мкс 434 мкс 1.0 нет
    vk-io 755 903 25 170 3.9 мс 11 мс 2.9 нет
    Telegram umbot 20 369 920 678 320 138 мкс 444 мкс 1.0 нет
    grammy 9 262 307 608 мс 1 135 мс 63.9 нет
    telegraf 6 266 207 852 мс 1 836 мс 66.2 нет
    Alisa umbot 17 500 009 583 037 185 мкс 554 мкс 1.3 нет
    dialogs-sdk 80 716 2 687 68 мс 103 мс 17.3 нет
    Viber umbot 22 731 200 757 386 127 мкс 403 мкс 1.0 нет
    viber-bot 193 107 6 435 16 мс 37 мс 0.3 нет
    MAX umbot 19 879 695 662 382 150 мкс 435 мкс 1.0 нет
    max-bot-api 19 512 649 287 мс 426 мс 66.4 нет

    Утечка — retained-дельта после финального GC: у всех участников 0.0 КБ на 1000 запросов, куча не растёт от начала к концу теста.

    Исправление методики (3.1.0). В прежней версии стенда retained-память мерилась, пока массив задержек самого воркера (8 байт на запрос) был ещё жив. «Утечка» получалась пропорциональной числу запросов и штрафовала самого быстрого участника. Квантили теперь считаются до замера, массив освобождается; после исправления утечек нет ни у одного участника.

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

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

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

    Платформа Сценарий umbot: 1-й / ср. 200, мкс Конкурент: 1-й / ср. 200, мкс
    Telegram 6 команд, точное 1 303 / 14.1 grammy 720 / 14.8
    Telegram 1000 команд, точное 124 / 4.2 grammy 1 413 / 374.7
    Telegram 1000 команд, регулярка 1 687 / 46.4 grammy 3 490 / 423.9
    Alisa 6 команд, точное 1 675 / 17.4 dialogs-sdk 760 / 13.0
    VK 6 команд, точное 3 087 / 35.5 vk-io 978 / 11.3
    VK 1000 команд, точное 146 / 5.4 vk-io 501 / 54.8
    Viber 6 команд, точное 2 786 / 35.9 viber-bot 1 594 / 18.2
    MAX 6 команд, точное 1 444 / 18.4 max-bot-api 611 / 15.1

    Как читать: на малых базах первый запрос у umbot в 1.7–3 раза медленнее, чем у конкурентов (1.3–3.1 мс против 0.6–1.6 мс) — у umbot больше кода, который V8 компилирует при первом вызове (ленивая компиляция функций; кэш компиляции Node, NODE_COMPILE_CACHE, этого не убирает — проверено). Для serverless это 1–2 мс на холодный старт инстанса. Самый первый сценарий процесса (VK, Viber) дополнительно платит за загрузку модулей. С ростом числа команд umbot и в холодном старте впереди. Индексы поиска для больших баз строятся после регистрации команд, а первые запросы до сборки идут обычным перебором — первый запрос за сборку индексов не платит.

    Конкурент Тепличный стенд (13 сценариев) Стресс, 1000 команд (RPS) Память на апдейт
    grammy (Telegram) umbot быстрее во всех 13 678 320 против 307 (2 210×) umbot меньше везде (в 6–53 раза)
    telegraf umbot быстрее во всех 13 678 320 против 207 (3 277×) umbot меньше везде (в 7–57 раз)
    yandex-dialogs-sdk umbot быстрее во всех 13 583 037 против 2 687 (217×) umbot меньше везде
    vk-io 11 побед, 2 паритета (6 команд) 715 481 против 25 170 (28×) umbot меньше везде
    viber-bot umbot быстрее во всех 13 757 386 против 6 435 (118×) на 6 командах viber-bot меньше, дальше umbot
    max-bot-api 12 побед, 1 паритет (6 команд, точное) 662 382 против 649 (1 021×) umbot меньше везде

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

    • vk-io и max-bot-api на 6 командах — паритет: umbot быстрее на 0.1–0.3 мкс, но это меньше порога победы стенда.
    • Память на 6 командах против viber-bot: 2.1 против 1.5 КБ на апдейт (контроллер на каждый запрос и конвейер с async-обработкой).
    • Cold-start на малых базах — медленнее всех конкурентов (на ~0.6–2 мс на первый запрос).
    • Короткий прогрев на малых базах: пока V8 не оптимизировал горячий путь (первые ~20 000 запросов), umbot на 6 командах может быть на 0.1–0.2 мкс медленнее лёгких роутеров.

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

    • Рост числа команд: 0.8–2.1 мкс на любом сценарии со строковыми командами от 6 до 1000, 3.5–6.2 мкс на 1000 регулярок — против 26–760 мкс у конкурентов при 1000 командах.
    • Поведение под потоком на больших базах: 28–3 277× по пропускной способности, GC около 1%.
    • Утечки — нет ни у кого.

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

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

    umbot создан для:

    • навыков и ботов, управляемых текстом: команды, фразы, fallback-реакции, многошаговые диалоги (addStep), формы-опросники (addForm);
    • мультиплатформенности: одна бизнес-логика на 7 платформ (Алиса, Маруся, SmartApp, Telegram, VK, MAX, Viber) — включая голосовые с TTS, кнопками, карточками и NLU;
    • продуктов, где важна предсказуемая ресурсность: постоянное потребление памяти, отсутствие утечек (48-часовой стресс-тест), в 6–57 раз меньше мусора на запрос, чем у 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 при регрессии