第 12 章 功能开发参考指南
12.1. 开发 Go 功能
使用 Go 的 OpenShift Serverless 功能只是一个技术预览功能。技术预览功能不受红帽产品服务等级协议(SLA)支持,且功能可能并不完整。红帽不推荐在生产环境中使用它们。这些技术预览功能可以使用户提早试用新的功能,并有机会在开发阶段提供反馈意见。
有关红帽技术预览功能支持范围的更多信息,请参阅技术预览功能支持范围。
创建 Go 功能项目后,您可以修改提供的模板文件,以将业务逻辑添加到您的功能中。这包括配置功能调用和返回的标头和状态代码。
12.1.1. 先决条件
- 在开发功能前,您必须完成 配置 OpenShift Serverless 功能 中的步骤。
12.1.2. Go 功能模板结构
当使用 Knative (kn
) CLI 创建 Go 功能时,项目目录类似于典型的 Go 项目。唯一的例外是额外的 func.yaml
配置文件,用于指定镜像。
Go 功能有一些限制。唯一的要求是您的项目必须在 function
模块中定义,并且必须导出功能 Handle ()
。
http
和 event
触发器功能具有相同的模板结构:
模板结构
fn ├── README.md ├── func.yaml 1 ├── go.mod 2 ├── go.sum ├── handle.go └── handle_test.go
12.1.3. 关于调用 Go 功能
当使用 Knative (kn
) CLI 创建功能项目时,您可以生成一个响应 CloudEvents 的项目,或者响应简单 HTTP 请求的项目。Go 函数通过不同的方法调用,具体取决于它们是由 HTTP 请求还是 CloudEvent 触发。
12.1.3.1. HTTP 请求触发的功能
收到传入的 HTTP 请求时,将通过标准 Go Context 作为第一个参数来调用函数,后跟 http.ResponseWriter
和 http.Request
参数。您可以使用标准 Go 技术访问请求,并为您的功能设置对应的 HTTP 响应。
HTTP 响应示例
func Handle(ctx context.Context, res http.ResponseWriter, req *http.Request) { // Read body body, err := ioutil.ReadAll(req.Body) defer req.Body.Close() if err != nil { http.Error(res, err.Error(), 500) return } // Process body and function logic // ... }
12.1.3.2. 云事件触发的功能
收到传入的云事件时,由 CloudEvents Go SDK 调用该事件。调用使用 Event
类型作为参数。
您可以使用 Go Context 作为功能合同中的可选参数,如支持的功能签名列表中所示:
支持的功能签名
Handle() Handle() error Handle(context.Context) Handle(context.Context) error Handle(cloudevents.Event) Handle(cloudevents.Event) error Handle(context.Context, cloudevents.Event) Handle(context.Context, cloudevents.Event) error Handle(cloudevents.Event) *cloudevents.Event Handle(cloudevents.Event) (*cloudevents.Event, error) Handle(context.Context, cloudevents.Event) *cloudevents.Event Handle(context.Context, cloudevents.Event) (*cloudevents.Event, error)
12.1.3.2.1. CloudEvent 触发器示例
接收云事件,其中包含 data 属性中的 JSON 字符串:
{ "customerId": "0123456", "productId": "6543210" }
若要访问此数据,必须定义一个结构,用于映射云事件数据中的属性,并从传入事件检索数据。以下示例使用 Purchase
结构:
type Purchase struct { CustomerId string `json:"customerId"` ProductId string `json:"productId"` } func Handle(ctx context.Context, event cloudevents.Event) (err error) { purchase := &Purchase{} if err = event.DataAs(purchase); err != nil { fmt.Fprintf(os.Stderr, "failed to parse incoming CloudEvent %s\n", err) return } // ... }
另外,一个 Go encoding/json
软件包也可用于以字节阵列的形式直接以 JSON 形式访问云事件:
func Handle(ctx context.Context, event cloudevents.Event) { bytes, err := json.Marshal(event) // ... }
12.1.4. Go 功能返回值
HTTP 请求触发的功能可以直接设置响应。您可以使用 Go http.ResponseWriter 将该功能配置为执行此操作。
HTTP 响应示例
func Handle(ctx context.Context, res http.ResponseWriter, req *http.Request) { // Set response res.Header().Add("Content-Type", "text/plain") res.Header().Add("Content-Length", "3") res.WriteHeader(200) _, err := fmt.Fprintf(res, "OK\n") if err != nil { fmt.Fprintf(os.Stderr, "error or response write: %v", err) } }
云事件触发的功能可能会返回任何内容、error
或 CloudEvent
,从而将事件推送到 Knative Eventing 系统。在这种情况下,您必须为云事件设置唯一 ID
、正确的 Source
和 Type
。数据可以从定义的结构或者从一个 映射(map)
填充。
CloudEvent 响应示例
func Handle(ctx context.Context, event cloudevents.Event) (resp *cloudevents.Event, err error) { // ... response := cloudevents.NewEvent() response.SetID("example-uuid-32943bac6fea") response.SetSource("purchase/getter") response.SetType("purchase") // Set the data from Purchase type response.SetData(cloudevents.ApplicationJSON, Purchase{ CustomerId: custId, ProductId: prodId, }) // OR set the data directly from map response.SetData(cloudevents.ApplicationJSON, map[string]string{"customerId": custId, "productId": prodId}) // Validate the response resp = &response if err = resp.Validate(); err != nil { fmt.Printf("invalid event created. %v", err) } return }
12.1.5. 测试 Go 功能
Go 功能可以在您的计算机上进行本地测试。在使用 kn func create
创建函数时创建的默认项目中,有一个 handle_test.go
文件包含一些基本测试。这些测试可以根据需要扩展。
先决条件
- 在集群中安装了 OpenShift Serverless Operator 和 Knative Serving。
-
已安装 Knative (
kn
) CLI。 -
已使用
kn func create
创建功能。
流程
- 导航到您的功能的 test 文件夹。
运行测试:
$ go test