biconnector 26.1050.0 Ломающее

Biconnector 26.1050.0: локальный BI Конструктор без расширения лицензии блокируется

2 мин чтения Устаревших API: 1

Ломающее обновление

Удалены или изменены публичные API — прикладной код может перестать работать.

В коробку biconnector 26.1050.0 вышел 8 сентября 2026 года (дата из официального канала «Битрикс24 changelog»), и весь релиз про лицензирование локального режима BI Конструктора, в котором Superset работает на вашем сервере. Этому режиму теперь нужны расширение лицензии со сроком, регион ru и редакция Энтерпрайз или Холдинг, а портал с уже подключённым сервером без срока расширения блокируется. Разработчикам придётся заменить удалённый SupersetHostMode::handleSwitchMode() и дописать четыре метода в свои реализации IntegratorInterface.

Проверьте, не заблокирован ли ваш BI Конструктор

Решение о блокировке принимает новый SelfHostedAvailability. Он проходит цепочку проверок по данным портала и в сеть не ходит. Его isBlocked() пропускает только два состояния, Available и ExtensionGrace, а четыре остальных закрывают работу:

  • TariffUnavailable, редакция не подходит;
  • BoxLicenseExpired, истекла лицензия самой коробки. BoxLicenseTerm берёт License::getExpireDate(), доводит до конца дня и прибавляет 15 дней;
  • ExtensionMissing, срока расширения нет, опция ~bi_constructor_expired_at модуля main пуста;
  • ExtensionExpired, прошли срок расширения и 15 дней грейса после него.

Блокировка срабатывает в трёх местах. Новый middleware SelfHostedLicenseRestriction стоит первым в цепочке запросов SelfHostedIntegrator и на все управляющие запросы к серверу отвечает STATUS_INNER_ERROR, пропуская только четыре лицензионных. Эндпоинт bi_builder.php, который отдаёт строки данных, отвечает {"error":"LICENSE_EXPIRED"} и раз в сутки пишет предупреждение в лог. SupersetInitializer::startupSuperset() не запускает инстанс, если расширение не в состоянии Active.

Замок на дашборде, редиректы и ошибки в формах появляются в TariffUnavailable, ExtensionExpired и BoxLicenseExpired. Компоненты настроек, создания и редактирования дашбордов показывают ошибку с текстом состояния, прямая ссылка на дашборд ведёт обратно в список, публичная ссылка отдаёт STATUS = ERROR, а слайдеры импорта датасетов и внешних подключений редиректят на /. В ExtensionMissing пользователь видит только баннер, хотя bi_builder.php и управляющие запросы к серверу в этом состоянии отказывают так же, как в остальных.

Состояние портала можно прочитать из кода. Запустите это в своей консольной команде или на странице с подключённым прологом:

        <?php declare(strict_types=1);

use Bitrix\BIConnector\Superset\Selfhost\License\SelfHostedAvailability;
use Bitrix\BIConnector\Superset\Selfhost\License\SelfHostedLicense;
use Bitrix\BIConnector\Superset\Selfhost\SupersetHostMode;
use Bitrix\Main\Loader;

Loader::requireModule('biconnector');

$availability = SelfHostedAvailability::getInstance();
$license = SelfHostedLicense::getInstance();

$status = [
    'mode' => SupersetHostMode::getMode(),              // 'cloud' или 'selfhosted'
    'availability' => $availability->getState()->name,  // в облачном режиме здесь Available
    'blocked' => $availability->isBlocked(),
    'boxExpired' => $availability->isBoxLicenseExpired(),
    'extension' => $license->getState()->name,          // None, Active, Grace, Expired
    'extensionExpiry' => $license->getExpiryDate()?->format('Y-m-d'),
    'extensionBlockDate' => $license->getBlockDate()?->format('Y-m-d'),
    'switchErrors' => SupersetHostMode::checkSelfHostedRestrictions()->getErrorMessages(),
];

print_r($status);

    

getExpiryDate() вернёт null, если срока нет или значение опции отброшено. SelfHostedLicense принимает только целое число от 1767225600 (1 января 2026 UTC) до «сейчас плюс 10 лет», остальное выкидывает с предупреждением в логе. getBlockDate() прибавляет к сроку грейс, по умолчанию 15 дней. В switchErrors окажутся причины, по которым портал сейчас не пустят в локальный режим.

Кто записывает срок расширения, по коду не видно. В коде коробки на момент релиза ~bi_constructor_expired_at в bitrix/modules только читают, и только в biconnector, а комментарий в LicenseOption.php говорит, что её пишет лицензионный слой из полей обновления. Когда опция меняется, новый обработчик main:OnAfterSetOption_~bi_constructor_expired_at отправляет срок на сервер аналитики через SelfHostedLicenseSync.

О приближении срока будет напоминать агент SelfHostedLicenseNotifier::notifyExpiringLicense(). Раз в сутки он шлёт администраторам личные уведомления за 90 и за 30 дней до срока. Уведомление о восстановлении работы отправляет обработчик записи опции, SelfHostedLicenseSync::onExpiryDateOptionSet(), фоновой задачей и только если работа до этого останавливалась. В списке дашбордов администратор за 90 дней до срока увидит попап, а списки дашбордов и статистики использования выводят баннер.

Переход в локальный режим теперь с условиями

В 26.1000.0 handleSwitchMode() проверял только, что значение режима допустимое и портал не облачный. Теперь SupersetHostMode::checkSelfHostedRestrictions() проверяет по порядку:

  1. регион лицензии входит в ALLOWED_REGIONS = ['ru'];
  2. в License::getCodes() есть Enterprise или Holding, причём пустой реестр кодов считается разрешением;
  3. расширение в состоянии Active или Grace.

Отказы приходят с текстами BIC_SELFHOST_ERROR_REGION, BIC_SELFHOST_ERROR_EDITION и BIC_SELFHOST_ERROR_EXTENSION.

На странице настроек модуля вкладку локального режима в коробке видно, только если регион ru или портал уже в локальном режиме. Для перехода нужны адрес и пароль сервера, подключение должно пройти до переключения, а сразу после него страница вызывает SupersetInitializer::startupSuperset().

С грейсом вышла нестыковка. checkSelfHostedRestrictions() и SelfHostedAvailability в состоянии Grace разрешают и работу, и переключение, а startupSuperset() запускает инстанс только в Active. Портал, который переключили в локальный режим во время грейса, останется без запущенного инстанса.

Порталу вне ru, который уже работает в локальном режиме, вкладка видна, но сохранить настройки сервера он не сможет. SelfHostedConnectionService::updateConnectionSettings() первым делом проверяет регион и отвечает ошибкой, а страница показывает общее BIC_SUPERSET_CONNECTION_ERROR, по которому причину не понять.

Не выключайте локальный сервер до возврата в облако

Обратное переключение теперь зависит от локального сервера. applySwitchMode(MODE_CLOUD) сначала просит инстанс сбросить лицензионное состояние, для этого SelfHostedLicenseSync::resetInstanceLicenseState() вызывает на нём resetSelfHostedLicense(). Если сервер недоступен, отказал, бросил исключение, вообще не подключён или в этот момент идёт доставка срока, переключение отклоняется с BIC_SELFHOST_ERROR_LICENSE_RESET. Режим остаётся локальным, данные не удаляются.

Сначала переключите портал в облако и только потом гасите сервер. Блокировка этому не мешает, потому что лицензионные запросы, сброс в их числе, идут в обход middleware блокировки. Запись о сервере удаляет новый SelfHostedConnectionService::disconnectServer(), и если он не справится, переключение всё равно завершится.

Замените handleSwitchMode() парой методов

SupersetHostMode::handleSwitchMode(string $newMode): Result удалён, и вызов из вашего кода закончится фаталом Call to undefined method. Вместо него два метода. checkSwitchMode(string $newMode): Result только проверяет и ничего не меняет. applySwitchMode(string $newMode): Result переключает режим и удаляет данные того, из которого портал уходит. В докблоке сказано, что это не проверка и метод неидемпотентный. Режим, который уже включён, checkSwitchMode() пропускает без ошибок, а applySwitchMode() на нём не отказывает и снова стирает данные Superset, поэтому сравнивайте режим с getMode() до вызова, как это делает options.php.

Между проверкой и применением options.php вставляет свой шаг и подключает сервер через SelfHostedConnectionService::updateConnectionSettings(). Если переводите портал в локальный режим из своего кода, повторите ту же последовательность. Возврат в облако обходится без промежуточного шага:

        <?php declare(strict_types=1);

namespace Vendor\Bi\Application;

use Bitrix\BIConnector\Superset\Selfhost\SupersetHostMode;
use Bitrix\Main\Loader;
use Bitrix\Main\Result;

final class SupersetModeSwitcher
{
    public function switchToCloud(): Result
    {
        Loader::requireModule('biconnector');

        if (SupersetHostMode::getMode() === SupersetHostMode::MODE_CLOUD) {
            return new Result(); // на текущем режиме applySwitchMode() не отказывает, а заново стирает данные Superset
        }

        $check = SupersetHostMode::checkSwitchMode(SupersetHostMode::MODE_CLOUD);
        if (!$check->isSuccess()) {
            return $check;
        }

        // если локальный сервер не ответит, вернётся ошибка с текстом BIC_SELFHOST_ERROR_LICENSE_RESET
        return SupersetHostMode::applySwitchMode(SupersetHostMode::MODE_CLOUD);
    }
}

    

Проверьте свои реализации и наследников

В IntegratorInterface четыре новых метода, все возвращают IntegratorResponse:

  • setSelfHostedLicenseExpiration(?DateTime $date);
  • setBoxLicenseExpiration(?DateTime $date);
  • setSelfHostedEditionVerdict(bool $isAllowed);
  • resetSelfHostedLicense().

Своя реализация интерфейса без них перестанет загружаться, например та, которую подменяют через IntegratorFactory::setInstance(). В ядре их реализуют два класса. ProxyIntegrator отказывает локально, не отправляя запрос в прокси, со статусом STATUS_INNER_ERROR и кодами selfhosted_license_not_applicable, box_license_not_applicable, selfhosted_edition_verdict_not_applicable и selfhosted_license_reset_not_applicable. SelfHostedIntegrator передаёт их через команды Bitrix\Superset\Public\Commands\License\* модуля superset (они есть в superset 26.400.0), а те отправляют POST на /api/v1/bitrix/license/date/, box-date/, edition/ и reset/ инстанса, с таймаутами 5/15 с.

У BaseMenuItemCreator protected-метод createDashboardOpenEventFromMenu() получил третий параметр bool $isMarketAvailable = true, проверка маркета и тарифный слайдер переехали внутрь метода. Наследник, который его переопределяет, без нового параметра упадёт с фаталом при объявлении класса. IS_LOCKED у пунктов меню теперь считает новый protected isDashboardLocked(bool $isMarketAvailable = true), и пункт «Маркет» из getAdditionalItems() тоже получил IS_LOCKED.

Если вызываете SelfHostedConnectionService::updateConnectionSettings() сами, вне ru он теперь сразу возвращает ошибку. Одна транзакция внутри стала двумя, и адрес с токеном коммитятся до доставки срока лицензии. Когда генерация JWT-ключей или актуализация подключения срывается, новый приватный restorePreviousServer() возвращает прежние адрес и пароль.

SupersetInitializer::clearSupersetData() раньше удалял опции типизации датасетов, а теперь вызывает DatasetSettings::enableTypingForNewInstance(), и обе опции, TYPING_OPTION_NAME и TYPING_LOCK_OPTION_NAME, получают Y.

Выключатель проверки и длина грейса

Вручную настраиваются три опции модуля biconnector. selfhost_license_check_disabled = Y заставляет SelfHostedLicense::getState() всегда отвечать Active и один раз за запрос пишет об этом в лог. Проверки редакции и срока коробки он не отключает, так что TariffUnavailable и BoxLicenseExpired никуда не денутся. selfhost_license_grace_days и selfhost_box_license_grace_days задают длину грейса, по умолчанию 15 дней.

Комментарий в BoxLicenseTerm.php называет selfhost_box_license_grace_days инструментом для стенда и поддержки, а про selfhost_license_grace_days в SelfHostedLicense.php сказано «для стенда и тестов». По комментарию в SelfHostedLicense.php, инстанс считает свои 15 дней сам (SelfHostedLicenseService.GRACE_SECONDS на его стороне), поэтому константу SelfHostedLicense::GRACE_DAYS надо менять на обеих сторонах вместе. Опцию selfhost_license_grace_days инстанс не получает, и сокращённый ею грейс остановит портал раньше инстанса. selfhost_box_license_grace_days уже входит в срок коробки, который уходит на инстанс. Выключатель действует только на портале. Срок для инстанса SelfHostedLicenseSync берёт из getExpiryDate(), мимо getState(), и отправляет как есть.

БД, опции и агенты

Схема БД не менялась. В install/migrations/events.php добавлен обработчик main / OnAfterSetOption_~bi_constructor_expired_at → SelfHostedLicenseSync::onExpiryDateOptionSet. В b_option biconnector пишет служебные опции с префиксом ~selfhost_: отметки доставленных сроков и вердикта редакции, время и паузу следующего повтора, флаги предупреждений и ~selfhost_license_work_stopped.

Агенты SelfHostedLicenseSync::retryAgent(); (интервал 300 с, пауза между повторами удваивается до 3600 с) и SelfHostedLicenseNotifier::notifyExpiringLicense(); (раз в сутки) в install/migrations/agents.php не попали. Их ставит applySwitchMode() при переходе в локальный режим и снимает при выходе. Порталам, которые уже в локальном режиме, их по комментарию в SupersetHostMode.php ставит обновление. Скрипта обновления нам не видно, и проверить это мы не смогли.

Мелочи и находки

  • SelfHostedLicenseSync::deliverPendingEditionVerdict() читает previousVerdict для лога уже после Option::set(), поэтому в поле «предыдущий вердикт» попадает новое значение.
  • Там же бесхозный докблок про откладывание повторов висит прямо над докблоком readExpectedEditionVerdict(), а комментарий к isDeliveryPending() говорит о двух сроках, хотя доставляются три значения, вердикт и два срока.
  • Про EXTENDED_EDITION_CODES = ['Enterprise', 'Holding'] комментарий сам признаёт, что второй код избыточен. Реестр кумулятивный, и стенд с топовой редакцией несёт Portal,Communications,Enterprise,Holding.
  • В LicenseOption.php предупреждают, что имя опции срока менять нельзя, иначе все коробки молча потеряют лицензию.
  • Из options.php ушёл '' // TODO Add en article. Ссылку на инструкцию по развёртыванию теперь отдаёт LicenseLinks::getDeployGuideUrl(), вне СНГ она null, и строка не выводится. Ссылку экранирует htmlspecialcharsbx(), раньше она подставлялась в текст как есть.
  • Ветка сохранения адреса и пароля сервера проверяет режим через SupersetHostMode::getMode(), а не по $_REQUEST['superset_mode']. group_rights2.php в ветке сохранения страница подключает только при успехе.
  • Integration\Superset\Agent::notifyAllAdmins() был private, стал public. IntegratorFactory::getSelfHostedInstance() отдаёт локальный интегратор при любом текущем режиме.
  • В новой разметке страницы настроек, шаблонов и грида везде стоят data-testid="biconnector-selfhost-…", ARIA-роли и aria-describedby.

Что делать

  1. Если BI Конструктор у вас в локальном режиме, прочитайте состояние кодом из примера. При ExtensionMissing замков в интерфейсе нет, но bi_builder.php уже отвечает LICENSE_EXPIRED.
  2. Проверьте, что агенты SelfHostedLicenseSync::retryAgent(); и SelfHostedLicenseNotifier::notifyExpiringLicense(); есть в расписании.
  3. Переходите в локальный режим, когда checkSelfHostedRestrictions() без ошибок, а срок расширения в Active. В грейсе инстанс после переключения не запустится.
  4. Возвращаясь в облако, не выключайте локальный сервер, пока переключение не пройдёт.
  5. Поищите в коде handleSwitchMode(, свои реализации IntegratorInterface и наследников BaseMenuItemCreator, которые переопределяют createDashboardOpenEventFromMenu().

Устаревшие и удалённые API в этой версии

Символ Статус Чем заменять
Bitrix\BIConnector\Superset\Selfhost\SupersetHostMode::handleSwitchMode() Удалено Bitrix\BIConnector\Superset\Selfhost\SupersetHostMode::checkSwitchMode() + Bitrix\BIConnector\Superset\Selfhost\SupersetHostMode::applySwitchMode()

Читайте дальше

voximplant 26.700.0 Ломающее Свежее

Voximplant 26.700.0: оценку качества связи убрали, у notifyAdmins() появился тип

Модуль телефонии voximplant 26.700.0 вышел в коробочный Битрикс24 11 сентября 2026 года, по данным официального канала «Битрикс24 changelog». Из карточки звонка убрали оценку качества связи вместе с её JS-событиями, у `Im::notifyAdmins()` появился тип параметра, а публичные константы `SipStatusInfor...

3 мин
ui 26.687.0 Рутинное Свежее

UI 26.687.0: триал VibePlus в облаке и дизайн чипа TintedBitrixGpt

`Bitrix\UI\Controller\InfoHelper` при активации демо сначала спрашивает у модуля bitrix24, включён ли старт VibePlus, и если да, запускает триал VibePlus вместо обычного демо тарифа. Ветка срабатывает только при подключённом модуле bitrix24 и определённой константе `BX24_HOST_NAME`. В `ui.system.chi...

1 мин
ui 26.675.0 Ломающее Свежее

UI 26.675.0: ui.actionpanel переехал в бандл, а rich_text по-новому обходится с квадратными скобками

Модуль ui 26.675.0 собран 26 августа 2026. Из PHP поменялись `Converter` и `Whitelist` в `Bitrix\UI\Format\BBCode`, и пользовательские поля типа `rich_text` теперь иначе сохраняют и индексируют текст с квадратными скобками. На фронтенде старую панель групповых действий `ui.actionpanel` перевели на б...

4 мин
ui 26.650.0 Рутинное Свежее

UI 26.650.0: клавиатура в пикере реакций и аудио во вьюере

Релиз на 2 МБ, из PHP в нём только `config.php` расширений и номер версии. Пикером реакций теперь можно управлять с клавиатуры (роль `menu`, стрелки, Escape), у него появились опции `priorityReaction` и `contextAction` и методы `focus()` и `destroy()`. Если пикер привязан к кнопке, ссылке или элемен...

1 мин
Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.
AI Домовой

AI Домовой История

на связи

пишет…
Нет истории чатов
AI Домовой

Нужна авторизация

Войдите, чтобы задавать вопросы AI Домовому.

Войти