# 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 **500–700 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 **500–700 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:
`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
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.