構建屬於你自己的 dapr 綁定組件
在上一篇文章中,吐槽了拖延症的危害,因此這次我來分享一下我最新推送到 dapr 的最新的一個新的綁定組件,通過這個來看一下如何實現自己的綁定組件。
文中提到的 PR 可以在 dapr/components-contrib#872 查看對應的具體代碼。
什麼是 dapr 的綁定組件?
在 dapr 中,綁定是用於使用外部系統功能(比如事件或者接口)的擴展組件。它的優勢在於:
- 免除連接到消息傳遞系統 (如隊列和消息總線) 並進行輪詢的複雜性;
- 聚焦於業務邏輯,而不是如何與系統交互的實現細節;
- 使代碼不受 SDK 或庫的跟蹤;
- 處理重試和故障恢復;
- 在運行時在綁定之間切換;
- 構建具有特定於環境的綁定的可移植應用程序,不需要進行代碼更改;
在官方文檔中,也提到了一個具體的例子:以 twilio 發送短信爲例,一般開發過程中應用程序需要依賴 Twilio SDK 纔可以實現功能,但是藉助綁定組件,你可以將 SDK 的綁定轉移至 dapr 程序領域內,在本身應用程序中不再綁定對應的 SDK,不用擔心未來 SDK 過期或者變更帶來的重複工作(僅需要更新 dapr 即可)。
根據訂閱的進出方向,綁定組件也分爲輸入綁定和輸出綁定。這些綁定均是通過 yaml 文件描述類型和元數據,通過 HTTP/gRPC 進行調用。
如何實現自己的綁定組件?
官方例子中提供了一個基礎的介紹,上一節中我們也提到了在程序中,根據進出方向可以把綁定組件分爲輸出綁定和輸入綁定。你可以通過官方教程中的例子提供查看:
在這個例子用,你可以看到,根據方向吧 dapr 發佈消息到 Kafka 作爲輸出組件,把 Kafka 讀取消息到 dapr 作爲輸入組件。
綁定的聲明 yaml 文件的規範則如下:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: <NAME>
namespace: <NAMESPACE>
spec:
type: bindings.<TYPE>
version: v1
metadata:
- name: <NAME>
value: <VALUE>
其中metadata.name
則是綁定置名稱,spec.metadata.name
和spec.metadata.value
則是配置的屬性和對應值。這個值我們可以通過實現接口InputBinding
或者OutputBinding
實現輸入綁定和輸出綁定.
type InputBinding interface {
Init(metadata Metadata) error
Read(handler func(*ReadResponse) ([]byte, error)) error
}
type OutputBinding interface {
Init(metadata Metadata) error
Invoke(req *InvokeRequest) (*InvokeResponse, error)
Operations() []OperationKind
}
接下來需要實現一個生成對象的方法,比如說我們需要實現一個飛書推送 Webhook 的綁定組件,則可以:
type FeishuWebhook struct {
logger logger.Logger // 這個是dapr的日誌接口,輸出日誌可以使用這個
settings Settings // 具體配置信息
httpClient *http.Client // 請求HTTP
}
func NewFeishuWebhook(l logger.Logger) *FeishuWebhook {
// See guidance on proper HTTP client settings here:
// https://medium.com/@nate510/don-t-use-go-s-default-http-client-4804cb19f779
dialer := &net.Dialer{ //nolint:exhaustivestruct
Timeout: 5 * time.Second,
}
var netTransport = &http.Transport{ //nolint:exhaustivestruct
DialContext: dialer.DialContext,
TLSHandshakeTimeout: 5 * time.Second,
}
httpClient := &http.Client{ //nolint:exhaustivestruct
Timeout: defaultHTTPClientTimeout,
Transport: netTransport,
}
return &FeishuWebhook{ //nolint:exhaustivestruct
logger: l,
httpClient: httpClient,
}
}
在綁定組件生命週期中,init 會在初始化是進行調用,傳入我們之前在 yaml 文件中定義的配置文件,因此我們可以在這裏實現具體的配置獲取:
type Settings struct {
URL string `mapstructure:"url"` // Webhook地址
Secret string `mapstructure:"secret"` // 加密消息的密鑰
}
func (s *Settings) Decode(in interface{}) error {
return config.Decode(in, s)
}
func (s *Settings) Validate() error {
if s.ID == "" {
return errors.New("webhook error: missing webhook id")
}
if s.URL == "" {
return errors.New("webhook error: missing webhook url")
}
return nil
}
// Init performs metadata parsing
func (t *FeishuWebhook) Init(metadata bindings.Metadata) error {
var err error
if err = t.settings.Decode(metadata.Properties); err != nil {
return fmt.Errorf("feishu configuration error: %w", err)
}
if err = t.settings.Validate(); err != nil {
return fmt.Errorf("feishu configuration error: %w", err)
}
return nil
}
接下來在具體的Read(handler func(*ReadResponse) ([]byte, error)) error
和Invoke(req *InvokeRequest) (*InvokeResponse, error)
方法中,我們可以分別實現讀取傳入消息和發送傳出消息的功能。代碼根據不同實現而不同,這裏就不做區分了。
總結
我這裏根據實際的綁定組件例子介紹了給 dapr 實現綁定組件的功能,是不是手癢希望試試了?快點加入到貢獻大軍吧 XD。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://www.4async.com/2021/05/building-your-own-dapr-binding/