pulse-lets-go/docs/routing.md

120 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Routing
Маршрутизация звонков состоит из двух уровней:
1. **Routing Rules** — priority-based правила с regex-матчингом (first-match-wins)
2. **Balancing Mode** — стратегия выбора ноды внутри правила или глобально
## Routing Rules
Правила хранятся в `data/routes.json` и проверяются в порядке `Priority` (меньше = раньше). Первое совпавшее правило определяет маршрутизацию. Если правило не сработало (нода мертва / пул пуст) — переход к следующему. Если ни одно правило не совпало — глобальный `PickNode()`.
### Match Conditions (AND-логика)
Все непустые поля должны совпасть одновременно. Пустые поля — не проверяются.
| Поле | Тип | Описание |
|------|-----|----------|
| `match_caller_id` | regex | Caller ID звонящего |
| `match_destination` | regex | Номер назначения |
| `match_ingress_trunk` | regex | ID входящего транка |
| `match_days` | string | Дни недели: `"1-5"` (пн-пт), `"1,3,5"` (пн,ср,пт), `"6"` (сб). Воскресенье = 0 или 7 |
| `match_time_start` | `"HH:MM"` | Начало временного диапазона |
| `match_time_end` | `"HH:MM"` | Конец временного диапазона |
### Action Types
| Тип | Поле | Описание |
|-----|------|----------|
| `node` | `action_node_id` | Маршрутизация на конкретную ноду. Если нода dead/stale/lethal — fallthrough к следующему правилу |
| `pool` | `action_pool_ids` | Выбор лучшей ноды из заданного списка (по текущему режиму балансировки). Пустой/нездоровый пул — fallthrough |
| `auto` | — | Fallthrough к глобальному `PickNode()` с учётом режима балансировки |
### Пример правила
```json
{
"id": "rule-001",
"name": "VIP caller to dedicated pool",
"enabled": true,
"priority": 10,
"match_caller_id": "^7495",
"match_destination": "",
"match_ingress_trunk": "",
"match_days": "1-5",
"match_time_start": "09:00",
"match_time_end": "18:00",
"action_type": "pool",
"action_pool_ids": ["pbx-01", "pbx-02"],
"description": "VIP номера 7495 в бизнес-часы на выделенные ноды"
}
```
## Balancing Modes
Режим балансировки определяет, **как** выбирается нода из множества healthy-нод (после отсева lethal). Применяется как в глобальном `PickNode()`, так и внутри `pool`-правил.
### best
Выбирает ноду с **максимальным score** из кэша. O(1) — `bestScore` предрассчитывается при каждой метрике.
- Всегда одна и та же нода при одинаковых метриках — максимально нагружает лучшую ноду
- Хорошо для тестирования и сценариев где нужна предсказуемость
### weighted_random (по умолчанию)
Выбирает ноду **пропорционально score**: чем выше score, тем выше вероятность быть выбранной. O(n) — сканирует все ноды.
Алгоритм:
1. Отсеивает disabled, stale, lethal (score < 0)
2. Суммирует score всех кандидатов (`totalScore`)
3. `pick = rand(0, totalScore)`, идёт по кандидатам, вычитая score
4. Если `totalScore <= 0` равновероятный выбор
- Распределяет нагрузку пропорционально готовности
- Предсказуемость ниже, но утилизация выше менее загруженные ноды получают пропорционально меньше звонков
### Переключение режима
**Через API:**
```
PUT /api/route/mode
Authorization: Bearer <admin-jwt>
{"mode": "best"}
```
**Через конфиг:**
```json
{ "balance_mode": "weighted_random" }
```
Допустимые значения: `"best"`, `"weighted_random"`. API-эндпоинт сразу применяет режим и сохраняет в `config.json`.
## Routing Rules API
Правила маршрутизации CRUD `/api/routing/rules*`. Все эндпоинты требуют JWT (admin).
| Метод | Путь | Описание |
|-------|------|----------|
| `GET` | `/api/routing/rules` | Список всех правил (с hits) |
| `POST` | `/api/routing/rules` | Создать новое правило |
| `PUT` | `/api/routing/rules/{id}` | Обновить правило (частично) |
| `DELETE` | `/api/routing/rules/{id}` | Удалить правило |
| `PUT` | `/api/routing/rules/{id}/toggle` | Вкл/выкл: `{"enabled":true}` |
| `PUT` | `/api/routing/rules/reorder` | Новый порядок: `["rr-abc", "rr-def"]` переназначает Priority |
Правила хранятся в `data/routes.json` и применяются в порядке `Priority` (first-match-wins).
## Ответ /api/route
В ответе маршрутизации появилось поле `matched_rule` имя сработавшего правила (или `"none"` если правило не применилось):
```json
{
"node_id": "pbx-03",
"score": 88,
"sip_gateway": "sip:pbx03.lan:5060",
"matched_rule": "VIP to dedicated"
}
```