設定
設定檔預設在 etc/config.yaml;檔案不存在時該層被跳過,改用內建預設值加環境變數。其餘載入是 fail-loud:欄位型別錯誤或 secret 不合規,啟動直接失敗而不是帶病上線。
設定檔怎麼載入
Section titled “設定檔怎麼載入”設定由三層疊起來,後者覆寫前者:
- 內建預設值(程式碼裡;例如
server.addr是:8080、cache.driver是memory)。 etc/config.yaml——用GORTEXA_CONFIG=/path/to/config.yaml指到別處;檔案不存在時整層跳過。- 環境變數,格式
GORTEXA_<SECTION>__<FIELD>(區塊與欄位之間兩條底線)。
同一個欄位若在多層都設,最後生效的是環境變數。真實 secret 只走環境變數注入,不寫進 config.yaml、不進版控。
config.yaml
Section titled “config.yaml”server: addr: ":8080" shutdown_timeout: 20s enable_cors: true cors_origins: [] # CORS allowlist;enable_cors 只是總開關,沒列在這裡的 origin 拿不到 CORS headers openapi: true reflection: false # gRPC reflection 預設關
auth: jwt_secret: "dev-only-insecure-secret-change-me-please" issuer: "gortexa" # audience: "myapp" # 選配:設了之後簽出的 token 帶 aud、驗證時要求 aud——隔離共用 secret 的多個服務 ttl: 1h
db: dsn: "" # PostgreSQL DSN(Secret,日誌遮罩);走環境變數注入:GORTEXA_DB__DSN max_conns: 10
cache: driver: "memory" # "memory"(預設,process-local)或 "redis"
mq: driver: "nats" # "nats"(core,at-most-once)或 "jetstream"(durable,at-least-once) url: "" # 逗號分隔多 server,例 "nats://a:4222,nats://b:4222" group_id: "" # 空=fanout;非空=load-balance
log: level: "info" format: "json"
observ: service_name: "gortexa" service_version: "dev" # tracing_otlp: "localhost:4317" # OTLP trace endpoint;空值停用 # metrics_otlp: "localhost:4317" # OTLP metrics endpoint;空值停用(rate-limit/circuit-breaker 指標靠它) # logs_otlp: "localhost:4317" # OTLP log endpoint;空值停用 otlp_insecure: true # 只限本機 docker compose;連遠端一律 false sample_ratio: 1.0 genai_capture_content: false # 開啟後 MCP tool 呼叫的參數內容會進 telemetry # genai_mask_fields: ["password", "token", "secret", "authorization", "api_key"]快取:memory 與 redis
Section titled “快取:memory 與 redis”cache.driver 決定後端。預設 memory 不需要任何外部服務;redis 才讀 addr 以下的欄位。填了 memory 或 redis 以外的值,啟動會以 cache: unsupported driver 失敗。
cache: driver: "memory"Process-local,零外部依賴。適合單機部署與本機開發。
cache: driver: "redis" addr: "localhost:6379" password: "" # 走環境變數注入:GORTEXA_CACHE__PASSWORD db: 0
# 以下 client tunables 皆可省略,省略即用內建預設值 dial_timeout: 5s # 預設 5s read_timeout: 3s # 預設 3s write_timeout: 3s # 預設 3s pool_size: 10 # 預設 10;不可為負切到 redis 後由框架內建的零依賴 RESP client 連線,沒有第三方 redis 套件。
四個 tunable 的零值都代表「用內建預設」,所以只調你要動的那個就好:
| 欄位 | 預設 | 用途 |
|---|---|---|
dial_timeout |
5s | 建立連線的逾時 |
read_timeout |
3s | 單次讀取回應的逾時 |
write_timeout |
3s | 單次送出命令的逾時 |
pool_size |
10 | 連線池大小;0 用預設,負值被拒 |
資料庫(PostgreSQL)
Section titled “資料庫(PostgreSQL)”db.dsn 是 pgx 連線字串(Secret 欄位,日誌一律遮罩);db.max_conns 預設 10。真實 DSN 走環境變數注入:
GORTEXA_DB__DSN=postgres://user:pass@pgbouncer:6432/app連線池是 PgBouncer-safe 的:QueryExecModeExec、statement 與 description cache 皆關閉,放在 transaction-pooling 模式的 PgBouncer 後面不會因 prepared statement 出錯。
開發流程:schema 放 db/migrations/、SQL 放 db/queries/,跑 make sqlc 產生 type-safe 查詢碼到 internal/storage/db/。deploy/docker-compose.yaml 已含 postgres 與 PgBouncer,可供本機驗證。
環境變數覆寫
Section titled “環境變數覆寫”任何欄位都能用環境變數覆寫,格式 GORTEXA_<SECTION>__<FIELD>:
GORTEXA_SERVER__ADDR=:9090GORTEXA_AUTH__JWT_SECRET=<real-secret>GORTEXA_CACHE__DRIVER=redisGORTEXA_CACHE__ADDR=redis.internal:6379GORTEXA_SERVER__REFLECTION=trueSecret 規則
Section titled “Secret 規則”- config 中的 placeholder
dev-only-insecure-secret-change-me-please會被伺服器拒絕啟動,不可能誤帶上線。 - JWT secret 長度不足 32 bytes 也會被拒絕。
- 多個服務共用同一把 secret 與預設 issuer 時,彼此的 token 可以互通——要隔離就各自設
auth.audience(為 A 簽的 token 在 B 會被拒)。 - redis password、MQ URL(可能內嵌帳密)等 secret 欄位在日誌與錯誤輸出一律遮罩。
- 真實 secret 走環境變數注入,不進版控。
mq.group_id 決定訊息分派方式,兩個 driver 一致:
| group_id | NATS(core) | JetStream | 語意 |
|---|---|---|---|
| 空(預設) | Subscribe | ephemeral consumer | fanout:每個訂閱者都收到 |
| 非空 | QueueSubscribe | durable consumer(名稱=group_id,handler 成功才 ack) | load-balance:一則訊息一個處理者 |
driver 的差別在投遞保證:core NATS 是 at-most-once(無重投遞,handler 失敗訊息即消失);driver: "jetstream" 是 at-least-once——publish 等 server 落盤確認,handler 回錯誤會延遲重投遞,因此 handler 必須冪等。JetStream 需要 server 以 -js 啟動;框架對每個 topic 惰性自建 stream(保留 24h),operator 也可預建 stream 自訂保留策略——框架只採用、不改寫既有 stream。
gortexa doctor # 檢查 Go toolchain 與 proto 工具