# 內建元件

Source: https://gortexa.sheng.page/components/batteries/

`mq`、`cache`、`storage` 與 `client` 是四個可選的基礎設施 package：NATS／JetStream 訊息、預設 in-memory 的 cache、PgBouncer-safe 的 pgx 連線池，以及帶 OTel 儀表的出站 client。都可單獨引用，不用就不會被拉進來。

先取得模組：`go get github.com/yshengliao/gortexa@v0.28.3`。以下片段皆對 v0.28.3 編譯驗證過。

## mq

NATS 系的 pluggable pub/sub。`cfg.MQ.Driver` 選 `nats`（core、at-most-once）或 `jetstream`（durable、at-least-once、handler 須冪等）。`group_id` 空 = fan-out、非空 = load-balance。

```go
import "github.com/yshengliao/gortexa/mq"

pub, sub, err := mq.New(cfg.MQ)
if err != nil {
	return err
}
defer pub.Close(context.Background()) // ctx 是關閉預算：逾時先回傳，teardown 轉背景收尾
err = sub.Subscribe(ctx, "orders", func(ctx context.Context, m mq.Message) error {
	return handle(m.Value)
})
err = pub.Publish(ctx, "orders", mq.Message{Value: []byte("hello")})
```

`Message` 有 `Key`／`Value`／`Headers`。Headers 名稱有保留字：`gortexa-key` 與整個 `nats-*` 命名空間（不分大小寫，如 `Nats-Msg-Id`、`Nats-Expected-*`、`Nats-Rollup`）在所有 driver 上都會在 Publish 被拒為 `InvalidArgument`。也可直接用 `mq.NewNATS`／`mq.NewJetStream` 指定 driver。

## cache

預設 process-local in-memory，`cfg.Cache.Driver: redis` 可換分散式後端。

```go
import (
	"errors"
	"github.com/yshengliao/gortexa/cache"
)

c, err := cache.New(cfg.Cache)
if err != nil {
	return err
}
defer c.Close()
if err := c.Set(ctx, "k", []byte("v"), time.Minute); err != nil {
	return err
}
b, err := c.Get(ctx, "k")
if errors.Is(err, cache.ErrCacheMiss) {
	// key 不存在
}
```

## storage

建立 PgBouncer-safe 的 pgx 連線池，並附一個發 OTel DB span 的 query tracer。回傳 `*pgxpool.Pool`。

```go
import (
	"go.opentelemetry.io/otel"
	"github.com/yshengliao/gortexa/storage"
)

tracer := storage.NewDBTracer(otel.GetTracerProvider())
pool, err := storage.NewPool(ctx, cfg.DB, tracer) // tracer 傳 nil 則不發 span
if err != nil {
	return err
}
defer pool.Close()
```

## client

已接好 OTel 儀表的對外 client 建構子。

```go
import "github.com/yshengliao/gortexa/client"

conn, err := client.NewGRPCConn(client.GRPCClientConfig{Target: "svc:50051", Insecure: true})
if err != nil {
	return err
}
defer conn.Close()

hc := client.NewHTTPClient(client.HTTPClientConfig{Timeout: 5 * time.Second}) // 零值預設 30s
```

`Insecure: true` 只適用本機開發；正式環境走 TLS。

## 延伸閱讀

- [設定](https://gortexa.sheng.page/configuration/)：cache、MQ、storage 的設定鍵與語意
- [核心](https://gortexa.sheng.page/components/core/)：把這些元件接進 kernel 的組裝順序
- [完整範例](https://gortexa.sheng.page/examples/full-example/)：一份把所有東西接起來的 `main.go`
