1923

都内と業界の隅っこで生活しているエンジニアのノート

Azure Functions カスタム ハンドラー + Golang で Event Grid トリガーを試してみる

Azure Functions custom handler in Go に EventGridTrigger がなかったので試してみました。

カスタム ハンドラーの説明、その他のサンプルは以下にありますので、設定とコードのみざっくりと。

Event Grid トリガーでQueue Storage 出力の function.json です。

function.json

{
  "bindings":[
    {
      "type":"eventGridTrigger",
      "name":"eventGridEvent",
      "direction":"in"
    },
    {
      "name": "$return",
      "type": "queue",
      "direction": "out",
      "queueName": "test-output-node",
      "connection": "AzureWebJobsStorage"
    }
  ]
}
Name Trigger Input Output
eventGridTrigger Event Grid Event Grid Queue Storage

イベントを受信する部分は、GoCustomHandlers.goとちょっと変えて、ginを使ってみます。

main.go

package main

import (
    "encoding/json"
    "fmt"
    "github.com/gin-gonic/gin"
    "log"
    "net/http"
    "os"
)

func main() {
    customHandlerPort, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
    if !exists {
        customHandlerPort = "7071"
    }
    fmt.Println("FUNCTIONS_CUSTOMHANDLER_PORT: " + customHandlerPort)

    r := gin.Default()
    r.GET("/", home)
    r.POST("/EventGridTrigger", eventGridTriggerHandler)
    r.Run(":" + customHandlerPort)
}

func home(ctx *gin.Context) {
    ctx.JSON(http.StatusOK, nil)
}

func  eventGridTriggerHandler(ctx *gin.Context) {
    var req EventMessage
    if err := ctx.ShouldBindJSON(&req); err != nil {
        log.Fatalf(err.Error())
        return
    }

    var me EventGridData
    if val1, ok := req.Data["eventGridEvent"]; ok {
        jsonb, err := json.Marshal(val1)
        if err != nil {
            log.Fatalf(err.Error())
            return
        }
        if err := json.Unmarshal(jsonb, &me); err != nil {
            log.Fatalf(err.Error())
            return
        }
    }

    returnValue := HTTPResponse {}
    returnValue.Outputs.Res.Body = "OK"
    returnValue.Outputs.Res.StatusCode = "200"
    returnValue.ReturnValue = me.Data

    ctx.JSON(http.StatusOK, returnValue)
}
type HTTPResponse struct {
    Outputs struct {
        Res struct {
            Body       string `json:"body"`
            StatusCode string `json:"statusCode"`
        }                   `json:"res"`
    }
    Logs        []string
    ReturnValue interface{}
}

type EventMessage struct {
    Data map[string]interface{}
    Metadata map[string]interface{}
}

type EventGridData struct {
    Id string                 `json:"id"`
    Topic string             `json:"topic"`
    Subject string          `json:"subject"`
    Data struct {
        UserId int64            `json:"userId"`
        Name string                 `json:"name"`
    }                        `json:"data"`
    EventType string          `json:"eventType"`
    EventTime string          `json:"eventTime"`
    MetadataVersion string  `json:"metadataVersion"`
    DataVersion string      `json:"dataVersion"`
}

あとは、Azure上に必要なリソース作成してデプロイ。適当なカスタムトピック(Azure Event Grid イベント スキーマ)を送信して動作しましたので、お試しは完了です。

func SendTopic(url string) error {
    key1 := "****"
    msg := [1]Topic{}

    uid, err := uuid.NewRandom()
    if err != nil {
        log.Fatalf(err.Error())
    }
    msg[0].Id = uid.String()
    msg[0].Subject = "app/sample/test1"
    msg[0].EventType = "inserted"
    n := time.Now()
    msg[0].EventTime = n.Format(time.RFC3339)
    msg[0].Data.UserId = 1
    msg[0].Data.Name = "Example"
    msg[0].DataVersion = "1.0"
    json, _ := json.Marshal(msg)

    req, _ := http.NewRequest("POST", url, bytes.NewBuffer(json))
    req.Header.Set("aeg-sas-key", key1)
    client := new(http.Client)
    resp, err := client.Do(req)
    if err != nil {
        return err
    }
    defer func() {
        if resp.Body != nil {
            resp.Body.Close()
        }
    }()

    contents, err := ioutil.ReadAll(resp.Body)
    fmt.Println(string(contents))
    fmt.Println(err)
    if err != nil {
        return err
    }
    return err
}