11.5. 开发 Go 功能

重要

带有 Go 的 OpenShift Serverless 功能只是一个技术预览功能。技术预览功能不受红帽产品服务等级协议(SLA)支持,且功能可能并不完整。红帽不推荐在生产环境中使用它们。这些技术预览功能可以使用户提早试用新的功能,并有机会在开发阶段提供反馈意见。

有关红帽技术预览功能支持范围的更多信息,请参阅技术预览功能支持范围

创建 Go 功能项目后,您可以修改提供的模板文件,以将业务逻辑添加到您的功能中。这包括配置功能调用和返回的标头和状态代码。

11.5.1. 先决条件

11.5.2. Go 功能模板结构

当使用 Knative (kn) CLI 创建 Go 功能时,项目目录类似于典型的 Go 项目。唯一的例外是额外的 func.yaml 配置文件,用于指定镜像。

Go 功能有一些限制。唯一的要求是您的项目必须在 function 模块中定义,并且必须导出功能 Handle ()

httpevent 触发器功能具有相同的模板结构:

模板结构

fn
├── README.md
├── func.yaml 1
├── go.mod 2
├── go.sum
├── handle.go
└── handle_test.go

1
func.yaml 配置文件用于决定镜像名称和 registry。
2
您可以在 go.mod 文件中添加任何需要的依赖项,该文件可以包括额外的本地 Go 文件。为部署构建项目时,生成的运行时容器镜像中会包含这些依赖项。

添加依赖项示例

$ go get gopkg.in/yaml.v2@v2.4.0

11.5.3. 关于调用 Go 功能

当使用 Knative (kn) CLI 创建功能项目时,您可以生成一个响应 CloudEvents 的项目,或者响应简单 HTTP 请求的项目。Go 函数通过不同的方法调用,具体取决于它们是由 HTTP 请求还是 CloudEvent 触发。

11.5.3.1. HTTP 请求触发的功能

收到传入的 HTTP 请求时,将通过标准 Go Context 作为第一个参数来调用函数,后跟 http.ResponseWriterhttp.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
  // ...
}

11.5.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)

11.5.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)
  // ...
}

11.5.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)
  }
}

云事件触发的功能可能会返回任何内容、errorCloudEvent,从而将事件推送到 Knative Eventing 系统。在这种情况下,您必须为云事件设置唯一 ID 、正确的 SourceType。数据可以从定义的结构或者从一个 映射(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
}

11.5.5. 测试 Go 功能

Go 功能可以在您的计算机上进行本地测试。在使用 kn func create 创建函数时创建的默认项目中,有一个 handle_test.go 文件包含一些基本测试。这些测试可以根据需要扩展。

先决条件

  • 在集群中安装了 OpenShift Serverless Operator 和 Knative Serving。
  • 已安装 Knative (kn) CLI。
  • 已使用 kn func create 创建功能。

流程

  1. 导航到您的功能的 test 文件夹。
  2. 运行测试:

    $ go test

11.5.6. 后续步骤