跳到內容

核心概念

Protobuf 是單一事實來源。你只寫兩種東西:proto contract 和 logic 實作。gRPC stubs、HTTP/JSON gateway、OpenAPI spec、MCP tool schema 全部由 gortexa regen 從 proto 產生,流程固定是 buf lint → buf breaking → buf generate。

  • gen/ 下全是產物:不進版控、不手動編輯。
  • breaking-change gate 內建在流程裡:會破壞相容性的 proto 修改直接被擋下,additive 修改放行。

一個 cleartext HTTP/2 port,依 Content-Type 與路徑分派:

請求 去向
Content-Type: application/grpc gRPC(grpc-go 的 ServeHTTP 模式)
路徑 /mcp MCP bridge(Streamable HTTP)
其他 grpc-gateway(HTTP/JSON)與內建路由(/healthz/openapi.json

h2c 用的是 Go 原生 http.Server.Protocols,不是已棄用的 x/net/h2c。cleartext 表示部署時 TLS 必須在前面終結,見部署

八段、順序固定:

recover → request-id → logger → load-shed → rate-limit → circuit-breaker → auth → validation

鏈不完整時啟動直接失敗(fail-loud),不會默默少掛一段。OTel 以 gRPC StatsHandler 掛載,unary 與 streaming 都涵蓋。

順序固定,但 auth 段可插拔:預設是 HS256 JWT(interceptor.Config.Verifier),而 auth 段實際跑的是一個 auth.Authenticator——非 JWT 方案(static bearer/mTLS/API-key)改設 Config.Authenticator 即可,八段順序不變。要在鏈上加自己的 interceptor,用 kernel.WithServerOptions(...)(gRPC 會接在框架鏈之後、handler 之前,仍在 recover 之內),而非改動這八段。

鏈上三段治理的預設值定義在 cmd/server/main.go(不在 config.yaml——要調整就改 interceptor.NewSet 的參數重新編譯):

預設值 超限行為
rate-limit 每 peer 200 RPS、burst 100、追蹤 TTL 10 分鐘 RESOURCE_EXHAUSTED(HTTP 429)
circuit-breaker 連續 5 次失敗開路 10 秒、half-open 放 2 個探測 UNAVAILABLE(HTTP 503)
load-shed in-flight 上限 1,024(gRPC health 檢查豁免) RESOURCE_EXHAUSTED(HTTP 429)

量測數字(框架 README 的基準測試,Apple M1/go1.26.5):全鏈 unary 一趟約 1,552 ns、27 allocs;rate-limiter Allow 熱路徑 0 allocs(allocs 機器無關)。

一張對應表決定同一個錯誤在三個協議的輸出:gRPC status、HTTP status、MCP error envelope。原則是內部原因不外洩——只有 invalid-argument 與 unauthenticated 兩類會把訊息轉發給呼叫端,其餘類別一律回 registry 中的安全訊息。

錯誤解析熱路徑約 105 ns、2 allocs(用 Go 1.26 的 errors.AsType)。

組件 說明
Config 分層載入、fail-loud、secrets 遮罩。見設定
Health 三態健康對應 gRPC Health;app.Health().Register(...) 接真實依賴
Logging/Observability slog 結構化日誌 + OTLP 匯出
Database PgBouncer-safe 的 pgx pool + sqlc
Cache 預設 process-local in-memory;cache.driver: redis 切換分散式(零依賴 RESP client)
MQ NATS(core 或 JetStream);mq.group_id 空=fanout、非空=load-balance