perf(chat,update): пул воркеров per-user вместо сериальной очереди + HEAD-проба обновлений
- chat.Router: ограниченный пул chatWorkers=4 воркеров + FIFO-очереди per-user (userState/workerLoop/runUser). Порядок сообщений одного UserID сохраняется; разные пользователи обрабатываются параллельно (до 4 одновременных LLM-вызовов), long-poll Telegram не блокируется чужим аналитиком. Backpressure по jobs — только на перегруженного пользователя. - app.FreeChat: sessions под sync.Mutex (защита от data race при параллельных воркерах роутера). - update: ResolveLatest проверяет наличие бинаря HEAD-пробой без скачивания тела (fallback GET Range 0-0 при 405/501), сортировка версий по id убыв.; один общий http.Client (keep-alive) вместо нового на каждый запрос. - тесты: порядок/параллелизм per-user в router, HEAD-без-тела и фоллбэк на версию без бинаря в update. - память Serena: инварианты Router/update, примечания по форматированию на Windows.
This commit is contained in:
@@ -40,4 +40,15 @@
|
||||
## Версии
|
||||
- `app.Version` — семантическая major.minor.patch (ручной инкремент: patch=фиксы,
|
||||
minor=новая обратно-совместимая функциональность, major=несовместимые изменения). Сейчас 0.2.2.
|
||||
- `main.version` (ldflag) — build-идентификатор `commit-<sha7>`, отдельно от app.Version.
|
||||
- `main.version` (ldflag) — build-идентификатор `commit-<sha7>`, отдельно от app.Version.
|
||||
|
||||
## Форматирование (важно на Windows)
|
||||
- Репо на Windows-чекауте: `core.autocrlf=true` → файлы в рабочей копии с CRLF; `gofmt -l`
|
||||
на CRLF-копии шумит (глобально ~60 файлов). **Проверять формат только на LF-версии** (напр.
|
||||
`git -c core.autocrlf=false clone` во временный каталог) — так дифы видны корректно.
|
||||
- gofmt 1.26 форматирует doc-comments (`//` перед `go build ...` в `// go build` → пустая строка
|
||||
`//`) и выравнивание структур; не все файлы отформатированы по новой версии (предсуществующе).
|
||||
- CI (`go vet` + `go test`) формат не проверяет → gofmt-дифы не ломают сборку.
|
||||
- **Known race в тест-харнессе app:** `e2eChannel.Send` (`internal/app/e2e_test.go:213`) пишет
|
||||
`c.sent` без лока, тест читает с главной горутины → `-race` ловит в `TestE2ENotificationsOnTransitions`.
|
||||
Путь `worker→Notify→Send`; предсуществует, ещё не чинили (fix — мьютекс в `e2eChannel`).
|
||||
@@ -31,13 +31,15 @@ docs/ ui-spec.md — спека Fyne UI (слои, event-bus, fyne.Do
|
||||
## Ключевые инварианты
|
||||
|
||||
- **App.New-сигнатура:** `App.New(configPath, version, updateToken string, noUI bool)` (4-й параметр — headless; cgo-вариант собирается только при наличии C-компилятора).
|
||||
- **chat.Router:** асинхронная обработка входящих — **ограниченный пул `chatWorkers=4` воркеров + FIFO-очереди per-user** (`userState`, `workerLoop`/`runUser`). Порядок сообщений одного UserID сохраняется (флаг `scheduled` → один активный воркер на пользователя); разные пользователи обрабатываются параллельно (до 4 одновременных LLM-вызовов). Backpressure по `jobs` блокирует только перегруженного пользователя, не весь long-poll. `Processed()`/`WaitProcessed()` — синхронизация тестов.
|
||||
- **FreeChat** (app): `sessions map[uid]sessionID` защищён `sync.Mutex` (пишется из разных воркеров роутера).
|
||||
- **UI:** окно — ещё одна реализация `chat.Channel` (присоединяется в Router). Core не трогает UI; обмен — событийная шина (events). Кнопка «Завершить» = полный выход (SetOnQuit→cancel→UI.Run возвращается); закрытие крестиком = сворачивание, Core живёт. UI собирается с `--noui`/без cgo.
|
||||
- **Фазы аналитика (Decision.Phase):** `ask`, `propose`, `ready` (два последних обрабатываются одинаково в core), `abort`. Требования валидатора: ask — chat_reply/questions; propose — хотя бы одно изменённое поле; ready — без изменённых полей.
|
||||
- **Статусы задач (internal/model):** draft→collecting→ready→approved→running→success/failed/timeout + cancelled/aborted/closed (терминальные). UserID — chat.ID (одна активная задача на чат).
|
||||
- **Decider/Worker/Analyst/Reviewer:** Decider=analyst интерфейс; Worker — polling-планировщик; Reviewer проверяет diff dev-ветки (R1-R6), вердикт JSON {passed, critical_issues, solid_violations, comments}.
|
||||
- **gitops (worker):** worktree-режим; feature-ветка `feat/<taskTag>` от origin/main; push через http.extraHeader, токен Bearer.
|
||||
- **Пути «всё рядом с .exe»:** db/worktree резолвятся от ExeDir; config.yaml — рядом с бинарём, фоллбэк cwd.
|
||||
- **Автообновление:** авто = только Check+уведомление; замена — по /update; версии в `commit-<sha7>/` (не `latest/`); Verify сверяет предprod-версию (binary+в.в) .
|
||||
- **Автообновление:** авто = только Check+уведомление; замена — по /update; версии в `commit-<sha7>/` (не `latest/`); Verify сверяет контрольную сумму бинаря против `.sha256` той же версии. **Perf:** `ResolveLatest` проверяет наличие бинаря версии **HEAD-пробой без скачивания тела** (405/501 → fallback `GET Range: bytes=0-0`), сортировка версий по id убыв.; один общий `http.Client` (keep-alive). Ошибка U4 — только при несовпадении суммы (пустой/отсутствующий `.sha256` пропускает проверку — M1-известное замечание).
|
||||
|
||||
## opencode (v2 HTTP API, >= 1.18.18)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user