| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
## 1. В чём была проблема
У сессии gRPC-клиента (`TClientSession`) несколько таймеров на базе **`TGrpcTimer`** используют один и тот же механизм: внутри лежит **`grpc::Alarm`**, привязанный к **одному** `CompletionQueue`, события с которого обрабатывает **отдельный поток** poller (в логах и стеках — `ua_grpc_cq`).
**Публичные методы** `TGrpcTimer::Set` и `Cancel` вызывались **и с этого потока** (после срабатывания alarm, из колбэков завершения gRPC-операций, из `Poll` и т.д.), **и с других потоков** — например, при старте сессии из потока пула (`DoStart` → первый `MakeGrpcCallTimer->Set`). В результате **один и тот же** `grpc::Alarm` и связанные с ним поля таймера менялись **конкурентно без синхронизации**. ThreadSanitizer фиксировал **data race** внутри реализации alarm в gRPC; с точки зрения контракта это **недопустимое параллельное использование** обёртки над alarm.
Типичный конфликт: на потоке приложения выполняется **`Set`** (первый запуск таймера переподключения), параллельно на **`ua_grpc_cq`** обрабатывается завершение вызова и снова вызывается **`Set`** для отложенного переподключения — оба попадают в **`Alarm::Set`** для одного объекта.
---
## 2. Изменение архитектуры (как починили)
Инвариант: **любое изменение состояния `TGrpcTimer`, которое трогает `grpc::Alarm` и служебные поля таймера, выполняется только на потоке, который крутит `CompletionQueue::Next` для этого клиента** (тот же поток, что обрабатывает срабатывания alarm).
Для этого:
- Введены внутренние **`ApplySet` / `ApplyCancel`** — в них перенесена прежняя логика работы с alarm; вызывать их разрешено **только** в контексте poller.
- Публичные **`Set` / `Cancel`**: если вызов уже идёт **из** poller (определяется **thread-local** флагом на время обработки события из CQ), сразу вызываются **`Apply*`**; иначе работа **ставится в ту же** `CompletionQueue` через **искусственное завершение** (`grpc_cq_begin_op` / `grpc_cq_end_op`), а колбэк на стороне poller выполняет **`Apply*`**.
- Чтобы отложенная операция не обращалась к уже уничтоженной сессии, перед постановкой в очередь делается **`TryRef`** на **`TAsyncJoiner`** сессии; после выполнения **`Apply*`** — **`UnRef`**. Если сессия уже уходит в закрытие и joiner недоступен, отложенный **`Set`/`Cancel`** тихо отбрасывается.
С точки зрения **`client_impl`**, вызовы **`MakeGrpcCallTimer->Set`**, **`ForceCloseTimer->Set`**, **`PollTimer->Set`**, **`->Cancel`** **не менялись** — меняется только реализация внутри **`TGrpcTimer`** и конструктор (передаётся ссылка на **`AsyncJoiner`** сессии).
---
## 3. Новая архитектура: sequence diagram и пример
{% cut "Таблица потоков, примеры A/B и диаграммы Mermaid" %}
Ниже — **два типичных сценария** для одного таймера, например **`MakeGrpcCallTimer`** (переподключение после завершения gRPC-вызова).
### Где именно теперь «живёт» работа с таймером
| Действие | Поток |
| :--- | :--- |
| Публичный **`Set` / `Cancel`** с **стороны приложения** (не poller) | Постановка задачи в **CQ**; реальное **`Apply*`** — на **`ua_grpc_cq`**. |
| Публичный **`Set` / `Cancel`** уже **внутри** обработчика события CQ (вложенный вызов) | Сразу **`Apply*`** на том же потоке (**без** повторной постановки). |
| Срабатывание **`grpc::Alarm`** | Доставка в poller → **`TGrpcTimer::OnIOCompleted`** → при необходимости снова **`Alarm.Set`** / вызов пользовательского колбэка — **всё на `ua_grpc_cq`**. |
### Пример A: первый `Set` при старте сессии (поток приложения)
Сессия стартует в **`DoStart`** на **рабочем** потоке; **`MakeGrpcCallTimer->Set(Now())`** не трогает alarm напрямую — **ставит** в CQ задачу «выполнить **`ApplySet`**»; poller **выполняет** её и выставляет alarm.
```mermaid
sequenceDiagram
participant App as AppThread
participant Timer as TGrpcTimer
participant CQ as CompletionQueue
participant Poller as ua_grpc_cq
App->>Timer: Set(now)
Timer->>Timer: not poller thread
Timer->>Timer: TryRef(AsyncJoiner)
Timer->>CQ: enqueue synthetic op
CQ-->>Poller: Next delivers op
Poller->>Timer: deferred callback
Timer->>Timer: ApplySet(now)
Timer->>Timer: Alarm.Set + schedule
Timer->>Timer: UnRef(AsyncJoiner)
```
### Пример B: перепланирование после завершения вызова (уже на poller)
**`OnGrpcCallFinished`** вызывается с **CQ** после обработки тега gRPC; **`MakeGrpcCallTimer->Set(reconnectTime)`** попадает в **fast path** и сразу вызывает **`ApplySet`** на **`ua_grpc_cq`** — без очереди.
```mermaid
sequenceDiagram
participant Poller as ua_grpc_cq
participant Session as TClientSession
participant Timer as TGrpcTimer
Poller->>Session: OnGrpcCallFinished
Session->>Timer: Set(reconnectTime)
Timer->>Timer: poller thread (TLS)
Timer->>Timer: ApplySet(reconnectTime)
```
### Срабатывание alarm (напоминание)
Когда срабатывает **внутренний** alarm gRPC, poller получает тег **`TGrpcTimer`**, вызывает **`OnIOCompleted`**: там снова возможны **`Alarm.Set`** (перенос по **`NextTriggerTime`**) или переход к **пользовательскому** колбэку (**`MakeGrpcCall`**, **`Poll`**, **`BeginClose`** и т.д.) — **всё на том же потоке `ua_grpc_cq`**.
{% endcut %}
---
{% cut "Технические детали (файлы, API gRPC, TSAN, lifetime)" %}
### Файлы в Arcadia
| Файл | Роль |
| :--- | :--- |
| `library/cpp/unified_agent_client/grpc_io.h`, `grpc_io.cpp` | `TGrpcTimer`, `TPostedCompletion` / `TPostedBridge`, `PostIIOCallbackToCompletionQueue`, `TlsInUaGrpcCompletionQueuePoller` в цикле poller. |
| `library/cpp/unified_agent_client/client_impl.cpp` | Создание трёх `TGrpcTimer` с передачей `AsyncJoiner` сессии. |
### Низкоуровневая постановка в CQ
Паттерн тот же, что у **`TGrpcNotification::Trigger`**: **`grpc_core::ApplicationCallbackExecCtx`**, **`grpc_core::ExecCtx`**, **`grpc_cq_begin_op`**, **`grpc_cq_end_op`**. Тег **`CompletionQueueTag`** — отдельный объект; в **`FinalizeResult`** в poller передаётся **`IIOCallback`** (мост), который выполняет отложенную лямбду и освобождает себя после **`OnIOCompleted`**.
### TSAN ()
В отчёте TSAN конкурирующие записи шли в **`grpc::internal::AlarmImpl::Set`** из потока **`ua_grpc_cq`** (цепочка **`OnGrpcCallFinished` → `MakeGrpcCallTimer->Set`**) и из потока приложения (**`DoStart` → `MakeGrpcCallTimer->Set(Now())`**). После фикса оба пути сериализуют **`ApplySet`** на poller.
### Поведение при закрытии сессии
Если **`TryRef(AsyncJoiner)`** не удался, отложенный **`Set`/`Cancel`** не ставится — сессия уже в фазе **`Join`**. Уже стоящие в CQ задачи удерживают ref до выполнения **`Apply*`** и **`UnRef`**.
### Заглушка счётчика для `MakeIOCallback`
Для отложенной лямбды используется **`TNoOpRefStub`**: **`Ref`/`UnRef`** пустые; удержание сессии обеспечивается парой **`TryRef`/`UnRef`** на **`TAsyncJoiner`**, а не счётчиком **`TIOCallback`**.
{% endcut %}
commit_hash:ba05e9c98e41bcf748270a48a818cc7d233a161b
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Unified Agent: новый протокол стриминга и изменения в клиенте
Документ опирается на `library/cpp/unified_agent_client/proto/unified_agent.proto` и реализацию `TClientSession` в `client_impl.cpp`.
---
## 1. Новый протокол
**Legacy** — сессия без согласования версии: в ответе `Initialized` поле `protocol_version` отсутствует или равно **0**. Поведение соответствует старому контракту до появления опциональных полей согласования.
**Версионированный режим (v1 и выше)** — клиент объявляет максимально поддерживаемую версию (`accept_protocol_version`), агент возвращает **согласованную** версию `protocol_version` и опционально **opaque**-токен привязки сессии. Дальнейшие реконнекты с тем же `session_id` требуют передачи **доказательства** привязки (`session_binding_proof`), чтобы сервер мог отличить легитимное продолжение от подмены.
Семантика потока данных не меняется: после `Initialized` идут `DataBatch` / `Ack`, ретраи по `seq_no` и дедупликация на стороне агента при совпадении `session_id` и повторной отправке записей.
---
### 1.2. Новые поля
**Запрос `Request.Initialize`**
| Поле | Тип | Назначение |
|------|-----|------------|
| `accept_protocol_version` | `optional uint32` | Верхняя граница версии, которую клиент готов использовать (стиль HTTP Accept). **Не задано или 0** — клиент не предлагает новый протокол (legacy-only). |
| `session_binding_proof` | `bytes` | Доказательство привязки при реконнекте; используется, когда согласована версия **> 0** и у клиента есть токен от предыдущего `Initialized`. |
Поля `session_id`, `meta`, `shared_secret_key` — как раньше; `session_id` при реконнекте передаётся для дедупликации.
**Ответ `Response.Initialized`**
| Поле | Тип | Назначение |
|------|-----|------------|
| `protocol_version` | `optional uint32` | Согласованная версия: **min**(accept клиента, максимум сервера). **Не задано или 0** — сессия считается **legacy**. |
| `session_binding_token` | `bytes` | Непрозрачный токен: клиент обязан вернуть его в следующем `Initialize` как `session_binding_proof` при переподключении (для версий протокола **≥ 1**). |
Остальное без изменений: `session_id`, `last_seq_no`.
---
### 1.3. Процесс и логика выбора версии
1. Клиент задаёт **`MaxAcceptProtocolVersion`** (в коде: `SetMaxAcceptProtocolVersion`). Значение **0** означает: поле `accept_protocol_version` в `Initialize` **не отправляется** — только legacy.
2. Если `MaxAcceptProtocolVersion > 0`, в первом (и последующих) сообщении `Initialize` выставляется `accept_protocol_version = MaxAcceptProtocolVersion`.
3. Агент вычисляет согласованную версию как **min**(`accept_protocol_version`, собственный потолок поддерживаемых версий) и возвращает её в `Initialized.protocol_version`. Если клиент не прислал accept (legacy-only) или сервер отвечает **0** / не задаёт поле — на клиенте фиксируется **legacy** (`NegotiatedProtocol` сбрасывается).
4. При успешном `Initialized` с **`protocol_version > 0`** клиент сохраняет число версии в `NegotiatedProtocol` и копирует `session_binding_token` во внутреннее состояние для следующих коннектов.
#### Диаграмма обмена (Mermaid sequence)
Первое подключение с согласованием версии и привязкой:
```mermaid
sequenceDiagram
participant C as Клиент (TClientSession)
participant G as gRPC stream
participant A as Unified Agent
C->>G: открыть Session(stream Request / stream Response)
C->>A: Request.initialize<br/>accept_protocol_version = N (если N>0)<br/>session_id (опц.)<br/>meta, shared_secret_key, …
Note over A: min(N, server_max) → negotiated
A->>C: Response.initialized<br/>session_id<br/>last_seq_no<br/>protocol_version = negotiated<br/>session_binding_token (opaque)
C->>C: сохранить NegotiatedProtocol,<br/>SessionBindingToken, SessionId
loop Данные
C->>A: Request.data_batch (seq_no, payload, …)
A->>C: Response.ack (seq_no)
end
Note over C,A: обрыв стрима → реконнект
```
Реконнект при согласованной версии **> 0**:
```mermaid
sequenceDiagram
participant C as Клиент
participant A as Unified Agent
C->>A: Request.initialize<br/>session_id = сохранённый<br/>accept_protocol_version = N<br/>session_binding_proof = прежний token<br/>…
A->>C: Response.initialized<br/>session_id, last_seq_no,<br/>protocol_version, session_binding_token (может обновиться)
C->>A: Request.data_batch …
```
---
### 1.4. Восстановление сессии и обмен ключами
- **Идентификатор сессии:** `session_id` приходит от сервера в `Initialized` и дальше передаётся в `Initialize` при реконнекте — основа для дедупликации и продолжения с теми же `seq_no`.
- **Shared secret:** по-прежнему `shared_secret_key` в `Initialize` (если задан в параметрах клиента) — отдельный канал авторизации/проверки, не смешивается с биндингом стрима.
- **Привязка сессии (protocol v1+):** после первого успешного `Initialized` с `protocol_version > 0` клиент хранит `session_binding_token`. При следующем `PrepareInitializeRequest`, если есть `NegotiatedProtocol > 0` и непустой токен, в запрос кладётся `session_binding_proof` (содержимое токена). Так сервер связывает новый gRPC-стрим с прежней логической сессией.
- **Конфликт сессии:** при завершении gRPC-вызова с кодом **`ALREADY_EXISTS`** клиент **сбрасывает** `SessionId`, `NegotiatedProtocol` и `SessionBindingToken`, чтобы следующий коннект не повторял конфликтующий идентификатор и не слал устаревшее proof (см. `OnGrpcCallFinished` в `client_impl.cpp`).
---
### 1.5. Совместимость клиентов и серверов
| Клиент | Сервер | Результат |
|--------|--------|-----------|
| `MaxAcceptProtocolVersion = 0` | любой | Поле `accept_protocol_version` не отправляется; ожидается legacy-ответ (`protocol_version` 0 / отсутствует). Биндинг по токену не используется. |
| `MaxAcceptProtocolVersion > 0` | только legacy | Обычно `protocol_version` в ответе 0 или отсутствует — клиент остаётся в legacy для этой сессии. |
| `MaxAcceptProtocolVersion > 0` | поддерживает v1+ | Согласуется конкретное число (например 1); включаются `session_binding_token` / `session_binding_proof` на реконнектах. |
| Новый клиент | старый агент | Безопасный откат: нет обязательных новых полей в wire-format для legacy; сервер игнорирует неизвестные optional-поля (proto3). |
Важно: поведение «только новый протокол» для отдельных механизмов (например принудительная отмена стрима по неактивности) в клиенте завязано на **фактически согласованную** версию **`NegotiatedProtocol > 0`**, а не только на настройку `MaxAcceptProtocolVersion`.
---
## 2. Изменения в клиенте — исправления и защита от регрессий
Ниже — логика, связанная с новым протоколом и устойчивостью сессий (файл `client_impl.cpp`, заголовки `client.h` / `client_impl.h`).
1. **Согласование версии и биндинг** — `PrepareInitializeRequest` выставляет `accept_protocol_version` только при `MaxAcceptProtocolVersion > 0`; при наличии согласованной версии и токена добавляет `session_binding_proof`. `OnGrpcCallInitialized` выставляет `NegotiatedProtocol` и `SessionBindingToken` только если `protocol_version` задан и **> 0**, иначе очищает их (строгий legacy).
2. **Конфликт `ALREADY_EXISTS`** — при таком статусе завершения стрима сбрасываются `SessionId`, `NegotiatedProtocol` и `SessionBindingToken`, чтобы не зациклиться на неверной паре (session_id, proof) и не провоцировать повторные конфликты на стороне агента.
3. **Watchdog неактивности gRPC (`GrpcCallInactivityTimeout`)** — принудительное закрытие активного вызова (`BeginClose(true)`) и счётчик `GrpcCallsClosedByInactivity` выполняются **только** при `NegotiatedProtocol.Defined() && *NegotiatedProtocol > 0`. Для legacy и до первого успешного `Initialized` с ненулевой версией отмена по этому таймеру **не** выполняется; таймер перепланируется как раньше. Это устраняет нежелательное принудительное реконнект-поведение на транспортах, где ранее допускалось «молчание» без отмены (см. план по этому пути).
4. **Пост-fork дочерний процесс** — сброс `SessionId`, `NegotiatedProtocol`, `SessionBindingToken` вместе с очередями, чтобы дочерний процесс не унаследовал привязку чужой сессии.
Документация в публичном API: комментарий к `SetGrpcCallInactivityTimeout` в `client.h` описывает ограничение по согласованной версии протокола.
---
*При необходимости уточнения формулы `min(accept, server_max)` на стороне агента смотрите реализацию сервера в репозитории `logbroker/unified_agent` (обработка `Initialize` в gRPC-сессии).*
commit_hash:9d5ef1cdc0faf793b4f56bfd2bafa362d7995ac5
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
## Проблема
После аварийного завершения агента (SIGKILL) или длительной недоступности C++ клиент Unified Agent не восстанавливал соединение сам. Сессия оставалась в состоянии «активна», сообщения накапливались в буфере (inflight), при достижении лимита начинались потери (dropped messages), и доставка не возобновлялась даже после поднятия агента — требовался перезапуск приложения-клиента.
## Как исправлено
Добавлен механизм «страховки»: если у сессии есть не подтверждённые сообщения (inflight), но по активному gRPC-стриму долго нет никакой активности (ни read, ни write, ни finish), клиент принудительно отменяет текущий вызов и запускает обычный путь реконнекта (повторные попытки установки сессии). «Длительность молчания» задаётся новым параметром; по умолчанию механизм включён (30 с) — зависание сессии никому не нужно, отключить можно явно, выставив таймаут в 0.
{% cut "Технические детали" %}
**Корневая причина:** реконнект планировался только в `OnGrpcCallFinished`, то есть после завершения активного stream-вызова. При «зависшем» транспорте (transport stall после падения агента) gRPC мог не вызывать финальный callback, `ActiveGrpcCall` оставался занятым, и новый `MakeGrpcCall` не запускался.
**Изменения в коде:**
- В `TClientParameters` добавлен параметр `GrpcCallInactivityTimeout` (по умолчанию 30 с; 0 = отключено).
- В сессии заведён периодический watchdog-таймер; при срабатывании проверяется: есть ли активный `TGrpcCall`, есть ли inflight-сообщения и не было ли активности дольше заданного таймаута. При выполнении условий вызывается принудительное закрытие текущего call (`BeginClose(true)`), что приводит к `OnGrpcCallFinished` и планированию следующего `MakeGrpcCall` по `GrpcReconnectDelay`.
- Время последней активности обновляется при любом успешном событии стрима (Accept, Read, Write, Finish, а также при инициализации сессии и при ack).
**Тестирование:** добавлен интеграционный тест `TestReconnectAfterLongStall` (агент поднимается → сессия и первая доставка → убийство агента → отправка во время даунтайма → пауза → повторный запуск агента → проверка, что inflight обнуляется и сессия переинициализируется без рестарта приложения). Регрессии по существующим reconnect-тестам не наблюдаются.
{% endcut %}
commit_hash:f55efec2cff20fa975500e73d60ee57654abb2e0
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
# Улучшения библиотеки логирования и переход на троттлинг логов
## Описание
Этот PR содержит улучшения системы логирования unified\_agent с акцентом на предотвращение флуда логов и добавление метрик логирования.
## Основные изменения
### 1. Улучшения библиотеки логирования (`library/cpp/unified_agent_client/logger`)
- **Встроенный троттлинг логов**: Добавлена поддержка ограничения частоты логирования на уровне библиотеки
- Новые макросы `YLOG_*_T` с автоматическим троттлингом (20 логов на 10 секунд по умолчанию)
- Независимый троттлинг для каждой точки логирования (по `__FILE__:__LINE__`)
- Автоматический подсчет подавленных сообщений с выводом `[+N suppressed]`
- **Метрики логирования**: Добавлены счетчики для мониторинга активности логирования
- `RecordsReceived` - общее количество попыток логирования
- `RecordsDropped` - количество подавленных сообщений из-за троттлинга
- Счетчики передаются через `TLogger::TCounters` при создании логгера
- **Оптимизация производительности**:
- Использование `GetCycleCount()` для быстрого получения времени (вместо системных вызовов)
- Relaxed memory ordering для атомарных операций (достаточно для троттлинга)
- Минимальные накладные расходы при отключенном логировании
### 2. Переход всех логов агента на троттлинг
- **Унификация макросов**: Все макросы `YLOG_*` в `logbroker/unified_agent/common/util/logger.h` теперь используют троттлинг
- `YLOG_DEBUG`, `YLOG_INFO`, `YLOG_WARNING`, `YLOG_ERROR` и т.д. теперь автоматически применяют троттлинг
- Старые макросы `YLOG_*_F` теперь алиасы для новых троттлированных версий
- Обратная совместимость полностью сохранена
- **Обновление документации**: Файл `for_ai_cpp.md` обновлен с новыми рекомендациями по логированию
### 3. Интеграция метрик логирования в телеметрию
- **Новые счетчики в `TAgentLogCounters`**:
- `RecordsReceived` - rate метрика `agent.log.records_received`
- `RecordsDropped` - rate метрика `agent.log.records_dropped`
- **Экспорт метрик**: Метрики логирования автоматически собираются и отправляются в телеметрию агента
- **Рефакторинг конструктора `TAgent`**:
- Упрощена передача счетчиков через структуру `TAgent::TCounters`
- Счетчики логирования передаются в `TLogger` при инициализации
### 4. Тесты
- **Перенос тестов**: Тесты логирования перемещены из `logbroker/unified_agent/tests/gtests/logger_tests` в `library/cpp/unified_agent_client/ut`
- **Расширенное покрытие**:
- Тесты базового троттлинга
- Тесты счетчика подавленных сообщений
- Тесты независимого троттлинга для разных точек логирования
- Тесты форматирования сообщений
- Тесты счетчиков метрик
### 5. Исправления и улучшения
- **Удаление дублирования кода**: Логика троттлинга теперь находится только в `library/cpp/unified_agent_client/logger.cpp`
- **Упрощение API**: Удален отдельный файл `logbroker/unified_agent/common/util/logger.cpp`
- **Обновление импортов**: Все файлы обновлены для использования правильных заголовочных файлов
## Преимущества
1. **Защита от флуда логов**: Автоматическое ограничение частоты логирования предотвращает переполнение логов
2. **Наблюдаемость**: Метрики логирования позволяют отслеживать активность и проблемы с логированием
3. **Производительность**: Минимальные накладные расходы благодаря оптимизированной реализации
4. **Простота использования**: Троттлинг работает автоматически, не требует изменений в коде
5. **Обратная совместимость**: Все существующие макросы продолжают работать
## Тестирование
- ✅ Все unit-тесты логирования проходят
- ✅ Integration тесты обновлены (исключение нестабильной метрики `RecordsReceived` из сравнений)
- ✅ Проверена работа троттлинга в реальных условиях
commit_hash:75fc97a8576114446bfb9ec11efbb80df322e443
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
## Problem
Log spam with repeated ``'max inflight of [***] bytes reached, [***] bytes dropped'`` errors appearing multiple times within the same second, causing log flooding.
## Solution
Implemented one-second throttling mechanism for this specific error message to prevent log spam while maintaining accurate counter tracking.
## Testing
- Added `TestMaxInflightBytesThrottling` integration test
- Confirms throttling limits log entries to ≤3 for 50 rapid message drops (vs 50 without throttling)
- Ensures all dropped message counters remain accurate regardless of throttling
commit_hash:58f44ca8ce2b8b416586f8ca7a3d3ca971f1e9cb
|
| |
|
|
|
|
|
| |
fintech, games, geobase, infra, ipreg, juggler, kernel, keyboard, laas, library, logbroker, logos, mail
If you think that this pr has broken something for you, roll it back
commit_hash:df8e48b2a4ecbbc74a504aa3ff62ebb8f464218d
|
| |
|
|
| |
https://clubs.at.yandex-team.ru/arcadia/29404
|
| | |
|
| | |
|
| | |
|
| |
|
| |
Correct order of the GRPC_ENABLE_FORK_SUPPORT set
|
| |
|