Compare commits

..

1 Commits

Author SHA1 Message Date
299a416f51 docs: accept ADR-0061 (Go handler refactor), supersede ADR-0004 (msgpack→protobuf)
All 5 handler services + companions-frontend migrated to handler-base v1.0.0
with protobuf wire format. golangci-lint clean across all repos.
2026-02-21 15:46:24 -05:00
2 changed files with 28 additions and 20 deletions

View File

@@ -1,6 +1,6 @@
# Use MessagePack for NATS Messages # Use MessagePack for NATS Messages
* Status: accepted * Status: superseded by [ADR-0061](0061-go-handler-refactor.md) (Protocol Buffers)
* Date: 2025-12-01 * Date: 2025-12-01
* Deciders: Billy Davies * Deciders: Billy Davies
* Technical Story: Selecting serialization format for NATS messages * Technical Story: Selecting serialization format for NATS messages

View File

@@ -1,7 +1,8 @@
# Refactor NATS Handler Services from Python to Go # Refactor NATS Handler Services from Python to Go
* Status: proposed * Status: accepted
* Date: 2026-02-19 * Date: 2026-02-19
* Decided: 2026-02-21
* Deciders: Billy * Deciders: Billy
* Technical Story: Reduce container image sizes and resource consumption for non-ML handler services by rewriting them in Go * Technical Story: Reduce container image sizes and resource consumption for non-ML handler services by rewriting them in Go
@@ -9,6 +10,8 @@
The AI pipeline's non-inference services — `chat-handler`, `voice-assistant`, `pipeline-bridge`, `tts-module`, and the HTTP-forwarding variant of `stt-module` — are Python applications built on the `handler-base` shared library. None of these services perform local ML inference; they orchestrate calls to external Ray Serve endpoints over HTTP and route messages via NATS with MessagePack encoding. The AI pipeline's non-inference services — `chat-handler`, `voice-assistant`, `pipeline-bridge`, `tts-module`, and the HTTP-forwarding variant of `stt-module` — are Python applications built on the `handler-base` shared library. None of these services perform local ML inference; they orchestrate calls to external Ray Serve endpoints over HTTP and route messages via NATS with MessagePack encoding.
> **Implementation note (2026-02-21):** During the Go rewrite, the wire format was upgraded from MessagePack to **Protocol Buffers** (see [ADR-0004 superseded](0004-use-messagepack-for-nats.md)). The shared Go module is published as `handler-base` v1.0.0 (not `handler-go` as originally proposed).
Despite doing only lightweight I/O orchestration, each service inherits the full Python runtime and its dependency tree through `handler-base` (which pulls in `numpy`, `pymilvus`, `redis`, `httpx`, `pydantic`, `opentelemetry-*`, `mlflow`, and `psycopg2-binary`). This results in container images of **500700 MB each** — five services totalling **~3 GB** of registry storage — for workloads that are fundamentally HTTP/NATS glue code. Despite doing only lightweight I/O orchestration, each service inherits the full Python runtime and its dependency tree through `handler-base` (which pulls in `numpy`, `pymilvus`, `redis`, `httpx`, `pydantic`, `opentelemetry-*`, `mlflow`, and `psycopg2-binary`). This results in container images of **500700 MB each** — five services totalling **~3 GB** of registry storage — for workloads that are fundamentally HTTP/NATS glue code.
The homelab already has two production Go services (`companions-frontend` and `ntfy-discord`) that prove the NATS + MessagePack + OpenTelemetry pattern works well in Go with images under 30 MB. The homelab already has two production Go services (`companions-frontend` and `ntfy-discord`) that prove the NATS + MessagePack + OpenTelemetry pattern works well in Go with images under 30 MB.
@@ -82,37 +85,42 @@ Chosen option: **Option 1 — Rewrite handler services in Go**, because the serv
## Implementation Plan ## Implementation Plan
### Phase 1: `handler-go` Shared Module ### Phase 1: `handler-base` Go Module (COMPLETE)
Create `git.daviestechlabs.io/daviestechlabs/handler-go` as a Go module with: Published as `git.daviestechlabs.io/daviestechlabs/handler-base` v1.0.0 with:
| Package | Purpose | Python Equivalent | | Package | Purpose | Python Equivalent |
|---------|---------|-------------------| |---------|---------|-------------------|
| `nats/` | NATS/JetStream client with msgpack encoding | `handler_base.nats_client` | | `natsutil/` | NATS publish/request/decode with protobuf encoding | `handler_base.nats_client` |
| `health/` | HTTP health + readiness server | `handler_base.health` | | `health/` | HTTP health + readiness server | `handler_base.health` |
| `telemetry/` | OTel traces + metrics setup | `handler_base.telemetry` | | `telemetry/` | OTel traces + metrics setup | `handler_base.telemetry` |
| `config/` | Env-based configuration (struct tags) | `handler_base.config` (pydantic-settings) | | `config/` | Env-based configuration (struct tags) | `handler_base.config` (pydantic-settings) |
| `clients/` | HTTP clients for LLM, embeddings, reranker, STT, TTS | `handler_base.clients` | | `clients/` | HTTP clients for LLM, embeddings, reranker, STT, TTS | `handler_base.clients` |
| `milvus/` | Milvus vector search client | `pymilvus` wrapper in handler_base | | `handler/` | Typed NATS message handler with OTel + health wiring | `handler_base.handler` |
| `messages/` | Type aliases from generated protobuf stubs | `handler_base.messages` |
| `gen/messagespb/` | protoc-generated Go stubs (21 message types) | — |
| `proto/messages/v1/` | `.proto` schema source | — |
Reference implementations: `companions-frontend/internal/` (NATS, msgpack, OTel), `ntfy-discord/internal/` (health, config, metrics). ### Phase 2: Service Ports (COMPLETE)
### Phase 2: Service Ports (in order of complexity) All five services rewritten in Go and migrated to handler-base v1.0.0 with protobuf wire format:
| Order | Service | Rationale | | Order | Service | Status | Notes |
|-------|---------|-----------| |-------|---------|--------|-------|
| 1 | `pipeline-bridge` | Simplest — NATS + HTTP + k8s API calls. Validates `handler-go` module. | | 1 | `pipeline-bridge` | ✅ Done | NATS + HTTP + k8s API calls. Parameters changed to `map[string]string`. |
| 2 | `tts-module` | Tiny NATS ↔ HTTP bridge to external Coqui API | | 2 | `tts-module` | ✅ Done | NATS ↔ HTTP bridge. `[]*TTSVoiceInfo` pointer slices, `int32` casts. |
| 3 | `chat-handler` | Core text pipeline — NATS + Milvus + HTTP calls | | 3 | `chat-handler` | ✅ Done | Core text pipeline. `EffectiveQuery()` standalone func, `int32(TopK)`. |
| 4 | `voice-assistant` | Same pattern as chat-handler with audio base64 handling | | 4 | `voice-assistant` | ✅ Done | Same pattern with `[]*DocumentSource` pointer slices. |
| 5 | `stt-module` (streaming) | Requires Go VAD bindings for the HTTP-forwarding variant | | 5 | `stt-module` | ✅ Done | HTTP-forwarding variant. `SessionId`/`SpeakerId` field renames, `int32(Sequence)`. |
### Phase 3: Cleanup `companions-frontend` also migrated: 129-line duplicate type definitions replaced with type aliases from handler-base/messages.
* Archive Python versions of ported services ### Phase 3: Cleanup (COMPLETE)
* Update Flux manifests for new Go images
* Update CI pipelines (Gitea Actions) for Go build/test/lint * ~~Archive Python versions of ported services~~ — Python handler-base remains for Ray Serve/Kubeflow
* Update CODING-CONVENTIONS.md with Go section * CI pipelines use `golangci-lint` v2 with errcheck, govet, staticcheck, misspell, bodyclose, nilerr
* All repos pass `golangci-lint run ./...` and `go test ./...`
* Wire format upgraded from MessagePack to Protocol Buffers (ADR-0004 superseded)
### What Stays in Python ### What Stays in Python