[2026-06-15] taiga-vault: personal/projects/zulip-router.md

This commit is contained in:
Taiga
2026-06-15 19:16:00 +00:00
parent 989f951b69
commit 7df11753ad
+94
View File
@@ -0,0 +1,94 @@
---
tags: [project, hermes, zulip, go, infra]
status: deployed
created: 2026-06-16
---
# Zulip Router
## Цель
Event-роутер между Zulip и несколькими Hermes-инстансами.
Решает проблему конкурентного получения событий (Валера, Клавдий и другие боты видели все сообщения одновременно, `reset` срабатывал у всех).
## Проблема (root cause)
- Каждый Hermes-инстанс в polling-режиме регистрирует собственную event queue в Zulip
- `reset` — системная команда Hermes, обрабатывается до хука `whale-thread-guard`
- Нет механизма ownership топика между инстансами
## Архитектура
```
Zulip Event Queue
↓ poll (valera-bot credentials)
[zulip-router]
├── @Валера → http://hermes-valera:8765/zulip-webhook
└── @Клавдий → http://hermes-klavdiy:8765/zulip-webhook
↕ ownership: stream+topic → bot (TTL 24h, persisted to /data/ownership.json)
```
Hermes/Орёл — не трогаем, остаётся в polling-режиме.
## Правила маршрутизации
1. `@Валера` или `@Valera` в тексте → Валера (+ ownership обновляется)
2. `@Клавдий` или `@Klavdiy` в тексте → Клавдий (+ ownership обновляется)
3. Топик уже у кого-то → туда же (TTL refreshed)
4. Новый топик без @mention → Валера (default)
5. `reset` без @mention → уходит только к владельцу топика ✓
## Код
`~/docker/zulip-router/` — Go, ~260 LOC
| Файл | Назначение |
|------|------------|
| `main.go` | Poll loop, routing, dispatch |
| `config.go` | Config struct + YAML loading + env var expansion |
| `zulip.go` | Zulip API client (register_queue, get_events, long-poll) |
| `ownership.go` | Topic ownership store (RW mutex + JSON persistence) |
| `forwarder.go` | HTTP POST к Hermes webhook endpoints |
## Deployment
**Compose:** `~/docker/hermes/docker-compose.yml` — сервис `zulip-router`
**Env vars** (`~/docker/hermes/.env`):
```
ZULIP_ROUTER_API_KEY=<valera-bot api key из ~/.hermes/profiles/valera/config.yaml>
ZULIP_WEBHOOK_TOKEN=zr-secret-2026
```
**Запуск после заполнения .env:**
```bash
cd ~/docker/hermes
docker compose up -d --force-recreate
```
**Перезапуск после изменений в профилях:**
```bash
docker compose restart hermes-valera hermes-klavdiy
```
## Hermes профили
Валера и Клавдий переведены в webhook-режим:
```yaml
platforms:
zulip:
webhook_port: 8765
webhook_path: /zulip-webhook
webhook_token: 'zr-secret-2026'
```
Токен должен совпадать с `ZULIP_WEBHOOK_TOKEN` в `.env`.
## TODO
- [ ] Заполнить ZULIP_ROUTER_API_KEY в ~/docker/hermes/.env
- [ ] `docker compose up -d --force-recreate`
- [ ] Проверить логи: `docker compose logs -f zulip-router`
- [ ] Протестировать: написать @Клавдий и @Валера в отдельных топиках
- [ ] Проверить ownership: обратиться в топик без @mention — должен отвечать последний бот
- [ ] При необходимости: добавить Hermes/Орёл в роутер (отдельная задача)