120 lines
5.8 KiB
Markdown
120 lines
5.8 KiB
Markdown
# 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"
|
||
}
|
||
```
|