
# 开发Go事件函数
关于Go函数的接口定义以及SDK接口说明请参考[Go函数开发概述](https://support.huaweicloud.com/devg-functiongraph/functiongraph_02_0504.html)。
#### 开发Go函数
登录已经安装了Go 1.x SDK的linux服务器，按照如下步骤进行编译和打包。（当前支持Ubuntu 14.04，Ubuntu 16.04，SuSE 11.3，SuSE 12.0，SuSE 12.1）
- [Go的版本支持go mod（go版本要求：1.11.1 及以上版本）]
  1. 创建一个临时目录例如"/home/fssgo"，将FunctionGraph的[Go RUNTIME SDK](https://function-community.obs.cn-north-1.myhuaweicloud.com/sdk/functiongraph-go-runtime-sdk-1.0.1.zip)解压到新创建的目录，并开启go module开关，操作如下：
     
     ```
     $ mkdir -p /home/fssgo
     $ unzip functiongraph-go-runtime-sdk-1.0.1.zip -d /home/fssgo
     $ export GO111MODULE="on"
     ```
     
     
  
  2. 在目录"/home/fssgo"下生成go.mod文件，操作如下，以模块名为test为例： 
     ```
     $ go mod init test
     ```
     
     
  
  3. 在目录"/home/fssgo"下编辑go.mod文件，添加加粗部分内容： 
     ```
     module test
     go 1.24.5
     require (
         huaweicloud.com/go-runtime v0.0.0-00010101000000-000000000000
     )
     replace (
         huaweicloud.com/go-runtime => ./go-runtime
     )
     ```
     
     
  
  4. 在目录"/home/fssgo"下创建函数文件，并实现如下接口： 
     func Handler(payload \[\]byte, ctx context.RuntimeContext) (interface{}, error)
     其中payload为客户端请求的body数据，ctx为FunctionGraph提供的运行时上下文对象，具体提供的方法可以参考[表19](https://support.huaweicloud.com/devg-functiongraph/functiongraph_02_0504.html#functiongraph_02_0504__table4315136814851)，以test.go为例：
     ```
     package main
     import (
         "fmt"
         "huaweicloud.com/go-runtime/go-api/context"
         "huaweicloud.com/go-runtime/pkg/runtime"
         "huaweicloud.com/go-runtime/events/apig"
         "huaweicloud.com/go-runtime/events/cts"
         "huaweicloud.com/go-runtime/events/dds"
         "huaweicloud.com/go-runtime/events/dis"
         "huaweicloud.com/go-runtime/events/kafka"
         "huaweicloud.com/go-runtime/events/lts"
         "huaweicloud.com/go-runtime/events/smn"
         "huaweicloud.com/go-runtime/events/timer"
         "encoding/json"
     )
     func ApigTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var apigEvent apig.APIGTriggerEvent
         err := json.Unmarshal(payload, &apigEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", apigEvent.String())
         apigResp := apig.APIGTriggerResponse{
            Body: apigEvent.String(),
            Headers: map[string]string {
               "content-type": "application/json",
            },
            StatusCode: 200,
         }
         return apigResp, nil
     }
     func CtsTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var ctsEvent cts.CTSTriggerEvent
         err := json.Unmarshal(payload, &ctsEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", ctsEvent.String())
         return "ok", nil
     }
     func DdsTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var ddsEvent dds.DDSTriggerEvent
         err := json.Unmarshal(payload, &ddsEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", ddsEvent.String())
         return "ok", nil
     }
     func DisTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var disEvent dis.DISTriggerEvent
         err := json.Unmarshal(payload, &disEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", disEvent.String())
         return "ok", nil
     }
     func KafkaTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var kafkaEvent kafka.KAFKATriggerEvent
         err := json.Unmarshal(payload, &kafkaEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", kafkaEvent.String())
         return "ok", nil
     }
     func LtsTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var ltsEvent lts.LTSTriggerEvent
         err := json.Unmarshal(payload, &ltsEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", ltsEvent.String())
         return "ok", nil
     }
     func SmnTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var smnEvent smn.SMNTriggerEvent
         err := json.Unmarshal(payload, &smnEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", smnEvent.String())
         return "ok", nil
     }
     func TimerTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var timerEvent timer.TimerTriggerEvent
         err := json.Unmarshal(payload, &timerEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         return timerEvent.String(), nil
     }
     func main() {
         runtime.Register(ApigTest)
     }
     ```
     **约束与限制：**
     1. 如果函数返回的error参数不是nil，则会认为函数执行失败。
     
     2. 如果函数返回的error为nil，FunctionGraph仅支持返回如下几种类型的值。 nil：返回的HTTP响应Body为空。
        \[\]byte：返回的HTTP响应Body内容为该字节数组内容。
        string：返回的HTTP响应Body内容为该字符串内容。
        其它：FunctionGraph会将返回值作为对象进行json编码，并将编码后的内容作为HTTP响应的Body，同时设置响应的"Content-Type"头为"application/json"。
        
     
     3. **上述例子使用APIG触发器的事件类型，如需使用其他触发器类型需要修改main函数的内容，例如使用CTS触发器则修改为runtime.Register(CtsTest)，目前只支持注册一个入口**。
     
     4. **当函数的事件源是APIG时，相关约束条件请参考** **[Base64解码和返回结构体的说明](https://support.huaweicloud.com/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li176282148442)** **。**
     
     
     
     
  
  5. 编译和打包 
     函数代码编译完成后，按照如下方式编译和打包。
     1. 编译
        ```
        $ cd /home/fssgo
        $ go build  -o handler test.go
        ```
        ![](https://support.huaweicloud.com/devg-functiongraph/public_sys-resources/note_3.0-zh-cn.png)
        "handler"作为函数执行入口可自定义，在FunctionGraph控制台的函数详情页设置中，可自行修改函数执行入口。
        
     
     2. 打包：
        ```
        $ zip fss_examples_go1.x.zip handler
        ```
        
     
     
     
     
  
  6. 创建函数 
     登录[函数工作流控制台](https://console.huaweicloud.com/functiongraph/?locale=zh-cn)，创建Go1.x函数，上传代码包**fss_examples_go1.x.zip**。
     对于Go runtime，必须在编译之后打zip包，编译后的文件名称必须与函数执行入口的名称保持一致，例如：二进制文件名为handler，则"函数执行入口"命名为handler，Handler与[步骤1]中定义的函数保持一致。
     
     
  
  7. 测试函数 
     1. 创建测试事件 在函数详情页，单击"配置测试事件"，弹出"配置测试事件"页，输入测试信息如[图1]所示，单击"创建"。
        图1配置测试事件   
        ![](https://support.huaweicloud.com/devg-functiongraph/zh-cn_image_0000002416544856.png "点击放大") 
     
     2. 在函数详情页，选择已配置测试事件，单击"测试"，参考[函数执行结果]查看函数执行结果。
     
     
     
     
   
- [Go的版本不支持go mod（go版本低于1.11.1）]
  1. 创建一个临时目录例如"/home/fssgo/src/huaweicloud.com"，将FunctionGraph的sdk [Go RUNTIME SDK](https://function-community.obs.cn-north-1.myhuaweicloud.com/sdk/functiongraph-go-runtime-sdk-1.0.1.zip)解压到新创建的目录，操作如下：
     
     **$ mkdir -p /home/fssgo/src** **/huaweicloud.com**
     **$ unzip functiongraph-go-runtime-sdk-1.0.1.zip -d /home/fssgo** **/src** **/huaweicloud.com**
     
     
  
  2. 在目录"/home/fssgo/src"下创建函数文件，并实现如下接口： 
     func Handler(payload \[\]byte, ctx context.RuntimeContext) (interface{}, error)
     其中payload为客户端请求的body数据，ctx为FunctionGraph提供的运行时上下文对象，具体提供的方法可以参考SDK接口，以test.go为例：
     ```
     package main
     import (
         "fmt"
         "huaweicloud.com/go-runtime/go-api/context"
         "huaweicloud.com/go-runtime/pkg/runtime"
         "huaweicloud.com/go-runtime/events/apig"
         "huaweicloud.com/go-runtime/events/cts"
         "huaweicloud.com/go-runtime/events/dds"
         "huaweicloud.com/go-runtime/events/dis"
         "huaweicloud.com/go-runtime/events/kafka"
         "huaweicloud.com/go-runtime/events/lts"
         "huaweicloud.com/go-runtime/events/smn"
         "huaweicloud.com/go-runtime/events/timer"
         "encoding/json"
     )
     func ApigTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var apigEvent apig.APIGTriggerEvent
         err := json.Unmarshal(payload, &apigEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", apigEvent.String())
         apigResp := apig.APIGTriggerResponse{
            Body: apigEvent.String(),
            Headers: map[string]string {
               "content-type": "application/json",
            },
            StatusCode: 200,
         }
         return apigResp, nil
     }
     func CtsTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var ctsEvent cts.CTSTriggerEvent
         err := json.Unmarshal(payload, &ctsEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", ctsEvent.String())
         return "ok", nil
     }
     func DdsTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var ddsEvent dds.DDSTriggerEvent
         err := json.Unmarshal(payload, &ddsEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", ddsEvent.String())
         return "ok", nil
     }
     func DisTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var disEvent dis.DISTriggerEvent
         err := json.Unmarshal(payload, &disEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", disEvent.String())
         return "ok", nil
     }
     func KafkaTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var kafkaEvent kafka.KAFKATriggerEvent
         err := json.Unmarshal(payload, &kafkaEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", kafkaEvent.String())
         return "ok", nil
     }
     func LtsTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var ltsEvent lts.LTSTriggerEvent
         err := json.Unmarshal(payload, &ltsEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", ltsEvent.String())
         return "ok", nil
     }
     func SmnTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var smnEvent smn.SMNTriggerEvent
         err := json.Unmarshal(payload, &smnEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         ctx.GetLogger().Logf("payload:%s", smnEvent.String())
         return "ok", nil
     }
     func TimerTest(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
         var timerEvent timer.TimerTriggerEvent
         err := json.Unmarshal(payload, &timerEvent)
         if err != nil {
            fmt.Println("Unmarshal failed")
            return "invalid data", err
         }
         return timerEvent.String(), nil
     }
     func main() {
         runtime.Register(ApigTest)
     }
     ```
     **约束与限制：**
     1. 如果函数返回的error参数不是nil，则会认为函数执行失败。
     
     2. 如果函数返回的error为nil，FunctionGraph仅支持返回如下几种类型的值。 nil：返回的HTTP响应Body为空。
        \[\]byte：返回的HTTP响应Body内容为该字节数组内容。
        string：返回的HTTP响应Body内容为该字符串内容。
        其它：FunctionGraph会将返回值作为对象进行json编码，并将编码后的内容作为HTTP响应的Body，同时设置响应的"Content-Type"头为"application/json"。
        
     
     3. **上述例子使用APIG触发器的事件类型，如需使用其他触发器类型需要修改main函数的内容，例如使用CTS触发器则修改为runtime.Register(CtsTest)，目前只支持注册一个入口**。
     
     4. **当函数的事件源是APIG时，相关约束条件请参考** [Base64解码和返回结构体的说明](https://support.huaweicloud.com/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li176282148442)。
     
     
     
     
  
  3. 编译和打包 
     函数代码编译完成后，按照如下方式编译和打包。
     1. 设置GOROOT和GOPATH环境变量：
        ```
        $ export GOROOT=/usr/local/go （假设Go安装到了/usr/local/go目录）
        $ export PATH=$GOROOT/bin:$PATH
        $ export GOPATH=/home/fssgo
        ```
        
     
     2. 编译：
        ```
        $ cd /home/fssgo
        $ go build  -o handler test.go
        ```
        ![](https://support.huaweicloud.com/devg-functiongraph/public_sys-resources/note_3.0-zh-cn.png)
        "handler"作为函数执行入口可自定义，在FunctionGraph控制台的函数详情页设置中，可自行修改函数执行入口。
        
     
     3. 打包：
        ```
        $ zip fss_examples_go1.x.zip handler
        ```
        
     
     
     
     
  
  4. 创建函数 
     登录[函数工作流控制台](https://console.huaweicloud.com/functiongraph/?locale=zh-cn)，创建Go1.x函数，上传代码包**fss_examples_go1.x.zip**。
     对于Go runtime，必须在编译之后打zip包，编译后的文件名称必须与函数执行入口的名称保持一致，例如：二进制文件名为handler，则函数配置中的"函数执行入口"需命名为handler，Handler与[步骤1]中定义的函数保持一致。
     
     
  
  5. 测试函数 
     1. 创建测试事件。 在函数详情页，单击"配置测试事件"，弹出"配置测试事件"页，输入测试信息如[图2]所示，单击"创建"。
        图2配置测试事件   
        ![](https://support.huaweicloud.com/devg-functiongraph/zh-cn_image_0000002394513545.png "点击放大") 
     
     2. 在函数详情页，选择已配置测试事件，单击"测试"，参考[函数执行结果]查看函数执行结果。
     
     
     
     
   
 #### 函数执行结果
执行结果由3部分组成：函数返回、执行摘要和日志。
表1执行结果说明 
| 参数项  | 执行成功                          | 执行失败                                                                                                                                                                                               |
|:---|:---|:---|
| 函数返回 | 返回函数中定义的返回信息。                 | 返回包含错误信息和错误类型的JSON文件。格式如下： ``` { "errorMessage": "", "errorType":"", } ``` errorMessage：Runtime返回的错误信息 errorType：错误类型 |
| 执行摘要 | 显示请求ID、配置内存、执行时长、实际使用内存和收费时长。 | 显示请求ID、配置内存、执行时长、实际使用内存和收费时长。                                                                                                                                                                      |
| 日志   | 打印函数日志，最多显示4KB的日志。            | 打印报错信息，最多显示4KB的日志。                                                                                                                                                                                 |
   
