ESPN DeportesCR7 pide suspender a fans por burlas a Diogo JotaRTP DesportoEuroVolley 2026. Portugal soma quarta derrota consecutiva frente à UcrâniaESPN'I'm willing to do whatever it takes': Inside the 274 days that rebuilt Patrick MahomesThe Jerusalem PostUS President Donald Trump shares his music taste with reporters in odd exchange on Air Force OnePunchNASEMA distributes relief materials to disaster, banditry victimsInquirerSenate approves on 3rd reading 5-year term of barangay, SK officials3DNewsИлон Маск помирился с Apple — но X Corp и SpaceXAI продолжат судиться с OpenAIBusiness AMDenemarken en VS streven naar diplomatieke oplossing voor geschil over GroenlandRapplerLIVE UPDATES: First BARMM parliamentary electionsAntara NewsChinese hiker injured on Indonesia's Mount Rinjani, SAR team deployedBillboardMacklemore Dropped From Ed Sheeran Tour Over His ‘Free Palestine’ CommentsCNN بالعربية"لكن أنا الذي أستحقها".. لامين يامال يسمّى منافسه الوحيد في سباق الكرة الذهبية 2026
The Daily Newsstand · Free, Always
Monday, September 14, 2026

redb 4.0: XML-маршруты, ленивые ссылки, уникальные ключи и WS-Trust в одном мажоре

Translate

Мажор всей экосистемы: что появилось в redb.Core, redb.Route, redb.Tsak и redb.Identity, что закрыто по безопасности и что ломает обновление.

Много работы было сделано ночами при свечах. Обратная связь от людей давала пищу для размышлений и фиксов: комментарии к статьям, обсуждения на GitHub, отчёты с живых стендов. И вот, отработав по-стахановски, выпускаю 4.0.0.

Это мажор всей экосистемы разом. Хранилище redb.Core, интеграционный движок redb.Route, рантайм redb.Tsak и OpenID-сервер redb.Identity выходят одним номером: 76 пакетов на NuGet (у 3.7 было 66), семь образов в GHCR, архивы под Windows и Linux. Pro-издание по-прежнему бесплатно и не требует лицензионного ключа на всей линии 4.x.

Изменений столько, что подробный разбор любого из продуктов тянет на отдельную статью, и такие статьи будут. Здесь коротко, почти списком: что появилось, что закрыто по безопасности и что нужно знать перед обновлением. Полные списки изменений лежат на redb.ru/releases.

redb.Route: маршруты в XML, тест-кит и форматы данных

Десять новых пакетов и заметная перестройка самого движка.

Общий словарь: книга EIP

Wire Tap, Content-Based Router, Splitter, Aggregator, Content Enricher, Claim Check, Idempotent Receiver: ни одно из этих названий не придумано для redb.Route. Все они из книги Грегора Хопе и Бобби Вулфа «Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions» (Addison-Wesley, 2003), каталога из 65 шаблонов обмена сообщениями. На этом каталоге построены Apache Camel, WSO2 Micro Integrator и redb.Route, поэтому он работает как общий словарь интеграции: узнав шаблон по названию, вы узнаете его в любом из этих инструментов. Глаголы DSL в redb.Route следуют написанию Camel: WireTapChoiceSplitAggregateEnrichClaimCheckIdempotentConsumer.

Весь каталог бесплатно доступен на сайте авторов, у каждого шаблона есть схема и короткое объяснение: enterpriseintegrationpatterns.com. Начинать стоит с глав о маршрутизации (Message Routing) и преобразовании сообщений (Message Transformation): форматы разных партнёров, трансляторы между ними и единая точка приёма разобраны там шаблон за шаблоном.

Новые пакеты

  • redb.Route.Xml. Маршрут описывается декларативно в .route.xml и загружается в тот же fluent DSL, что пишется на C#. Документ разбирается целиком при загрузке, и все ошибки приходят одним списком: неизвестный элемент с подсказкой, битое выражение, незарегистрированная схема эндпоинта. XSD генерируется из реестра элементов, context.xml описывает компоненты и бины контекста, генератор печатает XML обратно в C#. Хранилище redb доступно прямо из разметки через <redbGet> и <redbQuery>.

  • redb.Route.TestKit. Тест маршрута без брокеров и без правок в самом маршруте: AdviceRoute с ReplaceFromMockEndpoints("kafka://*")MockEndpoint с ожиданиями и сценарными ответами, NotifyBuilder. От тестового фреймворка не зависит.

  • redb.Route.Templates. Тело сообщения из шаблона Scriban или Liquid. Тип результата задаёт экранирование подставленных значений, шаблон компилируется при Start(), песочница не даёт вызывать методы.

  • redb.Route.DataFormats.Csv.Protobuf.Avro.Yaml, плюс Base64, GZip и Zip в самом redb.Route. У Protobuf и Avro есть обрамление Confluent.

  • redb.Route.JsonTransform. Преобразование JSON в JSON на JSONata с нативным .NET-движком.

  • redb.Route.Cache. Кэш как EIP: скоуп Cache(key, ttl)…EndCache() и компонент cache:, в памяти процесса или через любой IDistributedCache.

  • redb.Route.XPath2. XPath 2.0 для того, чего нет в 1.0: регулярные выражения, последовательности, ifforsome и every.

Движок

  • Один язык выражений. Условия, значения и ${...}-шаблоны идут через одну грамматику и один компилятор вместо трёх движков. Битое условие роняет Start(), а не превращается в константу на живом трафике. В языке появились stats(target, metric) со статистикой эндпоинтов, format(value, pattern, culture)uuid() и оператор %.

  • Компонент bean:. Пользовательский код как обычный эндпоинт: объект берётся из реестра контекста или создаётся с DI через конструктор, параметры URI биндятся на его свойства.

  • Перехваты и завершение в форме Apache Camel: InterceptInterceptFromInterceptSendToEndpointOnCompletion.

  • Агрегация без лямбд. Библиотека готовых AggregationStrategies (сбор тел в список, конкатенация, сумма, минимум и максимум по выражению, слияние в заголовок или свойство), Enrich без стратегии, throttle с лимитом из сообщения. AggregateRecipientListDynamicRouterIdempotentConsumerEnrich и PollEnrich принимают выражение, а не только делегат.

  • REST DSL в redb.Route.Http. Rest("/api/orders").Get("/{id}") с биндингом JSON, Consumes/Produces и OpenAPI 3.0.3 по адресу {basePath}/openapi.json.

  • Метрики изнутри маршрута. IExchange.Context и UseMetricsSnapshot(): слой OpenTelemetry читается прямо в процессе.

  • Без Newtonsoft.Json. jpath переехал на JsonPath.Net (RFC 9535) поверх System.Text.Json, и в зависимостях redb.Route осталась одна JSON-модель.

Нагрузка и хостинг

  • Лимиты приёма на эндпоинт. HTTP, SOAP, AS2 и gRPC получили maxConcurrentRequests и очередь ожидания: лишний запрос получает 429 с Retry-After до запуска конвейера, а соседний маршрут на том же порту свой бюджет не теряет. Отказы идут в отдельный счётчик Rejected, так что сброс нагрузки не путается с ошибками.

  • concurrentConsumers=auto у RabbitMQ, AMQP 1.0, IBM MQ, SQS и MQTT: число потребителей по числу процессоров, но не меньше двух. По умолчанию по-прежнему один, чтобы сохранялся порядок сообщений.

  • WebSocket и SignalR на общем Kestrel рядом с HTTP, gRPC, SOAP и AS2: один порт, аутентификация рукопожатия от хоста, шов для backplane при масштабировании.

  • Доверенные прокси на общем хосте. X-Forwarded-For проходится справа налево через все перечисленные прокси, X-Forwarded-Proto восстанавливает схему клиента, и каждый транспорт на хосте видит реальный адрес. Эту доработку подсказал комментарий к статье про 3.7.

Коннекторы

  • Kafka: коммит при отзыве партиции больше не теряет прочитанную, но не обработанную запись; seekTo отрабатывает по каждой партиции.

  • S3: консюмер больше не теряет объекты, настройки подключения доходят до AWS SDK.

  • Firebase: FCM multicast и управление топиками, копирование и подписанные URL в Storage, потоковое скачивание, databaseId для проектов Firestore с несколькими базами.

  • Llm: кэширование системного промпта у Anthropic со счётчиками токенов из кэша, фиксированная преамбула перед историей диалога, HTTP/2 keep-alive для длинных ответов через VPN и NAT, распознавание речи через stt:// и скачивание файлов из Telegram.

  • SOAP: консюмер обслуживает TLS, маршрут знает, кто его вызвал, и сам выбирает код fault.

  • TLS без сертификата больше нигде не открывает незашифрованный порт: WebSocket, SignalR и TCP в такой конфигурации отказываются стартовать.

redb.Core(.Pro): ленивые ссылки и уникальные ключи

Всё ниже работает одинаково на PostgreSQL, MSSQL и SQLite, во Free и в Pro.

  • Ленивые ссылки. Ссылка на границе глубины приходит заглушкой с id, схемой и хешем, и первое обращение к Props загружает ровно этот объект. Ссылку, которая должна быть ленивой на любой глубине, помечают virtual и включают EnableLazyReferences. Коллекция заглушек дозагружается одним запросом через LoadReferencesAsync, без N+1. Сохранение родителя, расчёт хеша и сериализация заглушки не будят.

  • Ключ объекта ValueUnique. Читаемая строка (номер заказа, артикул, внешний идентификатор), уникальная в рамках схемы, и upsert по ней через SaveByUniqueAsync.

  • [RedbUnique] на полях Props. Уникальность силами индекса базы для скаляров любого типа, включая decimal, даты и byte[]; для полей вложенных классов; для вложенного класса, массива или словаря целиком, где ключом становится содержимое поддерева; для элементов коллекции внутри объекта или по всей схеме. Поиск GetByUniqueAsync занимает одну пробу индекса, нарушение на трёх СУБД поднимается одним RedbUniqueViolationException. Дубли в уже накопленных данных попадают в отчёт, старт не падает.

  • Обновление схемы базы по контракту. Модуль схемы применяется при старте приложения. Если у роли нет прав менять схему, старт останавливается типизированным RedbSchemaOutdatedException, а скрипт для DBA отдают GetUpgradeScript() и redb schema --upgrade.

  • CancellationToken во всём асинхронном API. Отменённый SaveAsync откатывается полностью, а после коммита токен больше не читается: «отменено» никогда не означает «но всё-таки сохранено».

  • Интерцепторы записи IRedbSaveInterceptor в духе EF: SavingAsync может поправить объект или отменить сохранение, SavedAsync видит итог, то же самое для удаления. Под ChangeTracking интерцептор получает применённый дифф с путями свойств, из которого собирается собственный журнал аудита.

  • Уровень изоляции транзакции по запросу через BeginTransactionAsync(IsolationLevel) и DbErrorClassifier.IsSerializationFailure, чтобы повторять сериализуемые транзакции.

  • Maintenance: AnalyzeAsync обновляет статистику планировщика одним вызовом на любой СУБД, GetIndexStatsAsync читает состояние индексов.

  • LoadJsonAsync(id, depth) отдаёт объект сырым JSON без CLR-типа, а ToString() у RedbObject возвращает тот же канонический JSON.

  • byte[] хранится одним BLOB, а не строкой на каждый байт; старая раскладка конвертируется сама. Схема помнит namespace своего типа, и два Order из разных проектов больше не усыновляют схему друг друга.

  • Производительность: индексы на FK-колонках values, ускорение ChangeTracking, хеши в SQLite как BLOB(16), индекс на value_string теперь и на MSSQL.

  • Исправления, которые касались 3.x: сохранение родителя со ссылкой, заданной только по id, затирало объект за ссылкой; DateOnly на существующих базах читался как 0001-01-01; MSSQL обрезал вложенные ссылки в результатах LINQ на глубине 1, тогда как PostgreSQL и SQLite брали 10.

redb.Tsak: кластер на ключах базы и модули из XML

  • Кластер держится на уникальных ключах базы. Блокировки, узлы, группы и назначения модулей опираются на частичные уникальные индексы redb.Core. Два узла, стартующие на пустой базе, больше не создают два корня кластера: проигравший гонку принимает победителя. Запись назначения защищена номером эпохи лидера, и устаревший лидер не может посадить один модуль на два узла. Существующая база дозаполняет ключи сама при первом старте.

  • Модули из XML. .tpkg может нести только .route.xml и context.xml без единой сборки, и такой пакет перезагружается на лету так же, как модуль на C#. XML-маршрут в воркере видит все элементы разметки из shared-слоя: <cache><rest><redbGet>.

  • Дашборд различает сброс нагрузки и тишину. Панель Shedding Routes показывает маршруты, упёршиеся в лимит приёма, у эндпоинтов появились Rejected и Bytes Out. Автообновление страниц переживает разовую ошибку, графики мониторинга не замирают под курсором.

  • Страница About: версия дашборда и узла, аптайм, а для администратора список реально загруженных сборок redb.

  • Доверенные прокси: Tsak:Http:TrustedProxies принимает адреса и CIDR-сети, после чего троттлинг API-ключей и модульные маршруты видят реального клиента за цепочкой прокси.

  • Страницы Audit и Dead-letter работают на PostgreSQL. Вместе с ними на PostgreSQL впервые заработала ежедневная очистка tsak_audit_log, поэтому на узле, давно живущем на Postgres, перед первым прогоном стоит посмотреть размер этой таблицы.

  • Протокол кластера: heartbeat больше не откатывает одновременный cordon, узел в cordon не получает новых модулей, кластерный маршрут после остановки через API снова стартует.

  • Поставка под кластер: на общей базе Quartz в конфигурации по умолчанию работает в кластерном режиме (на SQLite он выключается сам, с предупреждением в логе), а ApiEndpoint узла определяется автоматически вместо общего для всех localhost:9090.

redb.Identity: WS-Trust, audience в токенах и консоль из страниц

  • WS-Trust фасад redb.Identity.Soap. Третий транспорт после HTTP и gRPC: IssueValidateCancel и Renew поверх SOAP для систем, которые строят клиента по WSDL. Издатель, реестр клиентов и хранилище токенов общие, так что клиент, зарегистрированный по HTTP, получает токен по SOAP. Без TLS фасад не стартует, есть mTLS с закреплением отпечатка сертификата.

  • Audience по RFC 9068 в access-токенах. Ресурсы выданных scope и новое поле приложения AccessTokenAudiences попадают в aud, а management API принимает только токены со своим audience.

  • Контракты отдельным пакетом-носителем. Горячая перезагрузка одного модуля больше не расщепляет общие DTO на две копии, из-за которых типизированное тело терялось по дороге через direct-vm://.

  • Уникальность на примитивах redb.Core. На MSSQL ключи ClientIdScopeName и ReferenceId впервые защищены индексом, а внешняя учётная запись больше не может гонкой привязаться к двум локальным пользователям.

  • Консоль администратора из страниц вместо диалогов. У провайдеров федерации появилась полноценная страница с маппингом claims, у маппера claims выбирается владелец правила, пользователь создаётся мастером, добавились каталог ресурсов API и дашборд с KPI и аудитом по категориям.

  • DPoP за прокси, терминирующим TLS, и правильный client_id в аудите для клиентов, которые передают учётные данные в теле формы.

Безопасность

Часть пунктов пришла внешними отчётами, часть найдена собственным аудитом фасадов и дашборда. Механика каждого будет в разборах по продуктам. Если у вас в проде 3.x, этот список сам по себе причина обновиться.

  • redb.Identity: HTTP-заголовок позволял выдать себя за любого пользователя. Внутренние заголовки теперь вычищаются на входе всех трёх фасадов: HTTP, gRPC и SOAP.

  • redb.Identity: страница согласия брала имя приложения и список scope из адреса, а форму согласия можно было отправить за другого пользователя без его сессии. Теперь страница строится из подписанного сервером билета, пользователь берётся только из сессии, формы проверяют Origin и не встраиваются во фрейм.

  • redb.Identity: introspect отвечал любому аутентифицированному клиенту по любому токену. Теперь только тем, кто входит в audience токена.

  • redb.Tsak: страницы дашборда открывались без входа. Теперь закрыта каждая страница, а уровни доступа совпадают с API воркера: аудит и пользователи для Admin, dead-letter и логи для Operator.

  • redb.Tsak: подпись модуля проверяется на всех путях загрузки, включая старт процесса, и загружаются ровно проверенные байты. Пароли не попадают в журнал аудита, сессии перепроверяются каждые пять минут, троттлинг входа считает пару из логина и адреса.

  • redb.Core: хешер паролей по умолчанию теперь bcrypt. Старые хеши SHA256 проходят проверку как раньше и переходят на bcrypt при следующей смене пароля.

Что ломает мажор

Список короткий, но пройти его стоит до обновления.

  • Кластеры redb.Tsak и redb.Identity обновляются остановкой. Узлы одной группы не должны работать на разных версиях: остановить всю группу, развернуть 4.0, запустить. Первый старт дозаполнит ключи.

  • Большой базе нужно окно обслуживания. Апгрейд добавляет колонки и строит частичные индексы под эксклюзивными блокировками. Удобнее заранее применить GetUpgradeScript() с одного узла и стартовать приложение с AutoApplyDatabaseUpgrades = false.

  • redb.Core: удалена ленивая загрузка Props целиком (EnableLazyLoadingForPropsWithLazyLoading(), параметр lazyLoadProps). objects.value_string ограничен 450 символами, и база с более длинными значениями откажет в апгрейде со списком объектов, которые нужно перенести в _note или Props. Обращение к Props ссылки за пределом глубины теперь идёт в базу; в Blazor WebAssembly для этого есть LazyReferenceAccess = Throw. Сборки, скомпилированные против 3.x, нужно пересобрать.

  • redb.Route: строковые LoopExpressionDelayExpression и ThrottleExpression стали LoopDelay и Throttle, а SetBodyExpression("…") и соседи стали SetBody(Expr("…")). Newtonsoft.Json больше не приезжает транзитивно. ${...} форматирует числа и даты инвариантно, ${...} в адресе консюмера роняет Start(), а ноль, "0""no" и "off" в условиях теперь ложь.

  • redb.Identity: backend, который интроспектирует токены другого клиента (классическая пара SPA и BFF), нужно добавить в AccessTokenAudiences этого клиента. Таблица аудита на SQLite сменила тип колонки времени, поэтому файлы аудита SQLite перед обновлением удаляются.

Как поставить

dotnet add package redb.Core
dotnet add package redb.Postgres        # или redb.MSSql / redb.SQLite
dotnet add package redb.Postgres.Pro    # Pro, бесплатно и без ключа

dotnet add package redb.Route
dotnet add package redb.Route.TestKit

Библиотеки таргетят net8.0net9.0 и net10.0, хостовые приложения и образы собраны на .NET 10. Tsak и Identity поставляются архивами под Windows и Linux (redb-tsakredb-identity) и образами в GHCR. Для первого знакомства с Tsak проще всего образ redb-tsak-stack, где воркер и дашборд живут в одном контейнере.

Пакеты: nuget.org/profiles/relikt. Исходники: github.com/redbase-app.

Что дальше

По каждому продукту выйдет отдельный разбор: redb.Core с кодом по ленивым ссылкам и ключам, redb.Route с тест-китом и XML-маршрутами, Tsak и Identity со своими историями. Для XML-маршрутов готовится расширение VS Code с текстовым режимом и графовым редактором.

Спасибо всем, кто писал комментарии, открывал обсуждения и присылал отчёты с продакшена: заметная часть этого релиза выросла именно оттуда.

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.