エントリリスナーとオブザーバー
エントリリスナーとオブザーバーは、一致するエントリ種別パターンのレジストリ変更を処理します。
これは Go 拡張リファレンスです。登録と設定の断片は、既存のブートコンポーネント、manager、transcoder、アプリケーション設定型を前提としています。
動作の仕組み
ブートはリスナーとオブザーバーを、その種別パターンとともに収集します。エントリが変更されると、次の処理が行われます。
- レジストリがイベント(
entry.create、entry.update、entry.delete)を発行 - 各リスナーラッパーがエントリ種別を登録済みパターンと照合
- 一致するハンドラがエントリを受信
- ハンドラがエントリを処理または reject
種別パターン
ハンドラはパターンを使用して subscribe します。
| パターン | 一致対象 |
|---|---|
http.service |
完全一致のみ |
http.* |
http.service、http.router、http.endpoint |
function.** |
function.lua、function.lua.bc |
エントリリスナーインターフェース
ハンドラは registry.EntryListener を実装します。
type EntryListener interface {
Add(ctx context.Context, entry Entry) error
Update(ctx context.Context, entry Entry) error
Delete(ctx context.Context, entry Entry) error
}
Add、Update、Delete からエラーを返すと、その操作を reject します。
リスナーとオブザーバー
| 種類 | 目的 | 拒否可能 |
|---|---|---|
| Listener | プライマリハンドラ | はい |
| Observer | セカンダリハンドラ(logging、metrics) | いいえ |
handlers.RegisterListener("http.*", httpManager)
handlers.RegisterObserver("function.*", metricsCollector)
オブザーバーの Add、Update、Delete から返されたエラーは無視され、accept または reject イベントを発行しません。TransactionListener も実装するリスナーまたはオブザーバーはトランザクション barrier に参加し、Begin、Commit、Discard からのエラーはそのトランザクションフェーズを reject します。
ハンドラの登録
ブート中にハンドラを登録します。
func MyService() boot.Component {
return boot.New(boot.P{
Name: "myservice",
DependsOn: []boot.Name{core.RegistryName},
Load: func(ctx context.Context) (context.Context, error) {
handlers := bootpkg.GetHandlerRegistry(ctx)
handlers.RegisterListener("myservice.*", manager)
return ctx, nil
},
})
}
エントリデータのデコード
system/entryのentry.DecodeEntryConfigを使用してエントリデータをアンマーシャルします。DecodeEntryConfigFromContextは引数の代わりにコンテキストからトランスコーダを取得し、DecodeEntryConfigRawはプレースホルダの解決をスキップします:
func (m *Manager) Add(ctx context.Context, ent registry.Entry) error {
cfg, err := entry.DecodeEntryConfig[ComponentConfig](ctx, m.dtt, ent)
if err != nil {
return err
}
// Process cfg...
return nil
}
デコーダーは:
-
${env:...}プレースホルダと*_envの対応フィールドを環境レジストリに対して解決 -
entry.Dataを設定構造体にアンマーシャル -
構造体が空のままの場合、エントリから
IDとMetaを設定 -
実装されていれば
InitDefaults()を呼び出し -
実装されていれば
Validate()を呼び出し -
エントリデータ内の新しい形式の
${env:...}プレースホルダーを解決 -
解決済みデータを設定構造体へ unmarshal
-
デコードしたフィールドが zero または nil の場合、エントリから
IDとMetaを設定 -
実装されていれば
InitDefaults()を呼び出す -
環境レジストリを通じて従来の
*_envフィールドを解決 -
実装されていれば
Validate()を呼び出す
設定構造体
エントリ設定には通常、次の要素が含まれます。
type ComponentConfig struct {
ID registry.ID `json:"id"`
Meta attrs.Bag `json:"meta"`
Name string `json:"name"`
Timeout int `json:"timeout,omitempty"`
}
func (c *ComponentConfig) InitDefaults() {
if c.Timeout == 0 {
c.Timeout = 30
}
}
func (c *ComponentConfig) Validate() error {
if c.Name == "" {
return fmt.Errorf("name is required")
}
return nil
}
トランザクション対応
複数エントリをまたぐ atomic な操作には TransactionListener を実装します。
type TransactionListener interface {
Begin(ctx context.Context) error
Commit(ctx context.Context) error
Discard(ctx context.Context) error
}
レジストリはバッチ処理前に Begin を呼び出し、成功時には Commit、失敗時には Discard を呼び出します。