本文介紹Go實(shí)現(xiàn)函數(shù)實(shí)例生命周期回調(diào)的方法。
背景信息
當(dāng)您實(shí)現(xiàn)并配置函數(shù)實(shí)例生命周期回調(diào)后,函數(shù)計(jì)算系統(tǒng)將在相關(guān)實(shí)例生命周期事件發(fā)生時(shí)調(diào)用對(duì)應(yīng)的回調(diào)程序。函數(shù)實(shí)例生命周期涉及Initializer、PreFreeze和PreStop三種回調(diào)。更多信息,請(qǐng)參見函數(shù)實(shí)例生命周期回調(diào)。
函數(shù)實(shí)例生命周期回調(diào)程序與正常調(diào)用請(qǐng)求計(jì)費(fèi)規(guī)則一致,但其執(zhí)行日志只能在函數(shù)日志、實(shí)例日志或高級(jí)日志中查詢,調(diào)用請(qǐng)求列表不會(huì)展示回調(diào)程序日志。具體操作,請(qǐng)參見查看實(shí)例生命周期回調(diào)函數(shù)日志。
回調(diào)方法簽名
- 初始化回調(diào)程序(Initializer回調(diào))是在函數(shù)實(shí)例啟動(dòng)成功之后,運(yùn)行請(qǐng)求處理程序(Handler)之前執(zhí)行。函數(shù)計(jì)算保證在一個(gè)實(shí)例生命周期內(nèi),成功且只成功執(zhí)行一次Initializer回調(diào)。例如您的Initializer回調(diào)第一次執(zhí)行失敗了,系統(tǒng)會(huì)重試,直到成功為止,然后再執(zhí)行您的請(qǐng)求處理程序。因此,您在實(shí)現(xiàn)Initializer回調(diào)時(shí),需要保證它被重復(fù)調(diào)用時(shí)的正確性。
- 預(yù)凍結(jié)回調(diào)程序(PreFreeze回調(diào))在函數(shù)實(shí)例凍結(jié)前執(zhí)行。
- 預(yù)停止回調(diào)程序(PreStop回調(diào))在函數(shù)實(shí)例銷毀前執(zhí)行。
function(ctx context.Context)
回調(diào)方法實(shí)現(xiàn)
// 注冊(cè)Initializer回調(diào)方法
fc.RegisterInitializerFunction(initialize)
// 注冊(cè)PreStop回調(diào)方法
fc.RegisterPreStopFunction(preStop)
// 注冊(cè)PreFreeze回調(diào)方法
fc.RegisterPreFreezeFunction(preFreeze)
package main
import (
"context"
"log"
"github.com/aliyun/fc-runtime-go-sdk/fc"
"github.com/aliyun/fc-runtime-go-sdk/fccontext"
)
func HandleRequest(ctx context.Context) (string, error) {
return "hello world!", nil
}
func preStop(ctx context.Context) {
log.Print("this is preStop handler")
fctx, _ := fccontext.FromContext(ctx)
fctx.GetLogger().Infof("context: %#v\n", fctx)
}
func preFreeze(ctx context.Context) {
log.Print("this is preFreeze handler")
fctx, _ := fccontext.FromContext(ctx)
fctx.GetLogger().Infof("context: %#v\n", fctx)
}
func initialize(ctx context.Context) {
log.Print("this is initialize handler")
fctx, _ := fccontext.FromContext(ctx)
fctx.GetLogger().Infof("context: %#v\n", fctx)
}
func main() {
fc.RegisterInitializerFunction(initialize)
fc.RegisterPreStopFunction(preStop)
fc.RegisterPreFreezeFunction(preFreeze)
fc.Start(HandleRequest)
}
func initialize(ctx context.Context)
:Initializer回調(diào)方法。其中ctx context.Context
參數(shù)提供了函數(shù)執(zhí)行時(shí)的上下文信息。更多信息,請(qǐng)參見上下文。func preStop(ctx context.Context)
:PreStop回調(diào)方法。其中ctx context.Context
參數(shù)提供了函數(shù)執(zhí)行時(shí)的上下文信息。更多信息,請(qǐng)參見上下文。func preFreeze(ctx context.Context)
:PreFreeze回調(diào)方法。其中ctx context.Context
參數(shù)提供了函數(shù)執(zhí)行時(shí)的上下文信息。更多信息,請(qǐng)參見上下文。- func main():運(yùn)行FC函數(shù)代碼的入口點(diǎn),Go程序必須包含
main
函數(shù)。通過添加代碼fc.Start(HandleRequest)
,設(shè)置請(qǐng)求處理程序的執(zhí)行方法;通過添加代碼fc.RegisterInitializerFunction(initialize)
,注冊(cè)Initializer回調(diào)方法。同理,注冊(cè)PreStop和PreFreeze回調(diào)方法。重要- 上述示例僅適用于事件請(qǐng)求處理程序(Event Handler)。如果是HTTP請(qǐng)求處理程序(HTTP Handler),您需要將示例中的
fc.Start(HandleRequest)
換成fc.StartHttp(HandleRequest)
。 - 注冊(cè)生命周期回調(diào)方法必須在
fc.Start(HandleRequest)
或fc.StartHttp(HandleRequest)
之前執(zhí)行,否則會(huì)導(dǎo)致注冊(cè)失敗。
- 上述示例僅適用于事件請(qǐng)求處理程序(Event Handler)。如果是HTTP請(qǐng)求處理程序(HTTP Handler),您需要將示例中的
配置生命周期回調(diào)函數(shù)
通過控制臺(tái)配置
在函數(shù)計(jì)算控制臺(tái)的FC函數(shù)配置中,啟用Initializer回調(diào)程序、PreFreeze回調(diào)程序和PreStop回調(diào)程序。示例如下。
具體步驟,請(qǐng)參見函數(shù)實(shí)例生命周期。
通過Serverless Devs配置
使用Serverless Devs配置
s.yaml
配置文件中添加Initializer 回調(diào)程序、PreFreeze 回調(diào)程序和PreStop 回調(diào)程序。
- Initializer回調(diào)配置
在function配置下添加initializer和initializationTimeout兩個(gè)字段。
- PreFreeze回調(diào)配置
在function配置下添加instanceLifecycleConfig.preFreeze字段,包括handler和timeout兩個(gè)字段。
- PreStop回調(diào)配置
在function配置下添加instanceLifecycleConfig.preStop字段,包括handler和timeout兩個(gè)字段。
s.yaml
文件中使用默認(rèn)值"true"
時(shí),必須攜帶雙引號(hào)。
具體的示例如下所示。
edition: 1.0.0
name: hello-world # 項(xiàng)目名稱
access: default # 密鑰別名
vars: # 全局變量
region: cn-shanghai # 地域
service:
name: fc-example
description: 'fc example by serverless devs'
services:
helloworld: # 業(yè)務(wù)名稱/模塊名稱
component: fc
props: # 組件的屬性值
region: ${vars.region}
service: ${vars.service}
function:
name: golang-lifecycle-hook-demo
description: 'fc example by serverless devs'
runtime: go1
codeUri: ./target
handler: main
memorySize: 128
timeout: 60
initializationTimeout: 60
initializer: "true"
instanceLifecycleConfig:
preFreeze:
handler: "true"
timeout: 30
preStop:
handler: "true"
timeout: 30
關(guān)于Serverless Devs的YAML配置規(guī)范,請(qǐng)參見Serverless Devs操作命令。
查看實(shí)例生命周期回調(diào)函數(shù)日志
您可以通過函數(shù)日志功能查看回調(diào)函數(shù)日志。
示例程序
函數(shù)計(jì)算為您提供了Initializer回調(diào)的示例程序。該示例為您展示了如何使用Go運(yùn)行時(shí)的Initializer回調(diào)來(lái)初始化MySQL連接池。在本示例中,MySQL數(shù)據(jù)庫(kù)配置在函數(shù)的環(huán)境變量配置中(參考s.yaml)。Initializer回調(diào)從環(huán)境變量中獲取數(shù)據(jù)庫(kù)配置,創(chuàng)建MySQL連接池并測(cè)試連通性。
更多信息,請(qǐng)參見go-initializer-mysql。