本文介绍如何通过控制台、Funcraft工具及SDK配置PreFreeze和PreStop函数。

背景信息

扩展函数简介

注意事项

  • PreFreeze和PreStop函数输入参数没有event参数。
  • PreFreeze和PreStop函数无返回值,在函数末尾增加返回逻辑是无效的。
  • 所有Runtime均支持配置PreStop函数;Python、PHP及C# Runtime不支持配置PreFreeze函数。
  • 如果使用Java Runtime,您需要将fc-java-core更新至1.4.0及以上版本,否则无法使用PreFreeze和PreStop扩展函数。

通过控制台配置

当您使用控制台创建函数时,函数计算不支持您配置PreFreeze及PreStop函数,您需要在更新函数时配置该参数。

  1. 登录函数计算控制台
  2. 在顶部菜单栏,选择地域。
  3. 在左侧导航栏中,单击服务及函数。在服务列表区域,单击目标服务。
  4. 函数列表页签找到目标函数,单击操作列的修改配置
    修改函数配置
  5. 修改配置页面,根据需要打开扩展函数开关,设置函数入口及超时时间,然后单击提交
    配置扩展函数
    说明 每一个扩展函数都需要配置单独的函数入口和超时时间,其中函数入口为[文件名].[扩展函数名]。例如在Python Runtime中,创建函数时指定的PreStop函数入口为index.preStopHandler,那么文件名为index.py,PreStop函数名为preStopHandler。
  6. 配置扩展函数的函数入口后,您需要在代码执行中实现对应的函数。
    1. 函数列表页签,单击目标函数名称。
    2. 单击代码执行页签,在代码执行管理区域,输入扩展函数代码。
      例如您配置了PreStop的函数入口为index.preStopHandler,则需要实现preStopHandler函数。关于不同Runtime中扩展函数的示例代码,请参见示例代码扩展函数代码

通过Funcraft工具配置

使用Funcraft工具配置PreFreeze、PreStop扩展函数时,配置文件示例代码如下所示:

  codeUri: ./
  ......
  InstanceLifecycleConfig:
    PreFreeze:
      Handler: index.PreFreeze
      Timeout: 60
    PreStop:
      Handler: index.PreStop
      Timeout: 60

如果您需要关闭某个扩展函数,需要将扩展函数的handler参数显示置空,否则后端默认不更新。例如关闭PreFreeze函数,您需要按照以下配置进行部署更新,此时PreFreeze函数的timeout参数已无效。

  codeUri: ./
  ......
  InstanceLifecycleConfig:
    PreFreeze:
      Handler: ""
      Timeout: 60
    PreStop:
      Handler: index.PreStop
      Timeout: 60

通过SDK配置

您可以通过SDK部署和更新扩展函数。本文以GO SDK为例,介绍在创建函数时配置PreStop和PreFreeze函数的示例代码:

package main

import (
  "github.com/aliyun/fc-go-sdk"
  "fmt"
  "os"
)

func main() {
  client, _ := fc.NewClient(
    os.Getenv("ENDPOINT"),
    "2016-08-15", 
    os.Getenv("ACCESS_KEY_ID"),
    os.Getenv("ACCESS_KEY_SECRET"),
  )

  serviceName := "ExtensionService"
  functionName := "ExtensionFunction"
  createFunctionInput := fc.NewCreateFunctionInput(serviceName).WithFunctionName(functionName)
  // 配置PreStop和PreFreeze函数。
  preStopHook := fc.NewLifecycleHook().WithHandler("index.preStop").WithTimeout(int32(30))
  preFreezeHook := fc.NewLifecycleHook().WithHandler("index.preFreeze").WithTimeout(int32(10))
  instanceLifecycle := fc.NewInstanceLifecycleConfig().WithPreStopHook(preStopHook).WithPreStopHook(preFreezeHook)
  createFunctionOutput, err := client.CreateFunction(createFunctionInput.WithInstanceLifecycleConfig(instanceLifecycle))
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
  } else {
    fmt.Printf("CreateFunction response: %s \n", createFunctionOutput)
  }
  return
}

示例代码

本文介绍不同Runtime下,扩展函数的实现Demo。相同Runtime下,PreFreeze和PreStop函数定义一致,因此本文仅介绍一种扩展函数的实现Demo。

 
# -*- coding: utf-8 -*-

import logging

def handler(event, context):
    logger = logging.getLogger()
    logger.info('handler start')
    return "ok"

def pre_stop(context):
    logger = logging.getLogger()
    logger.info('preStop start')
'use strict';

var counter = 0;
module.exports.handler = function(event, context, callback) {
    counter += 2;
    callback(null, String(counter));
};

module.exports.preFreeze = function(ctx, callback) {
    counter += 1;
    callback(null, "");
};
<?php      

$counter = 0;
function fc_func_pre_stop($context) {
    sleep(2);
}

function fc_func_handler($event, $context) {
    global $counter;
    $counter += 2;
    return $counter;
}
 ?>
      
using System;
using System.IO;
using Aliyun.Serverless.Core;

using Microsoft.Extensions.Logging;
namespace Aliyun.Serverless.TestHandlers
{
    public class PreStopAndPojoCounter
    {
        public int counter;
        public PreStopAndPojoCounter()
        {
            this.counter = 0;
        }

        public void PreStop(IFcContext context)
        {
            // todo
        }

        // todo
    }
}
import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.PreFreezeHandler;

import java.io.IOException;

public class PreFreezeNormal implements PreFreezeHandler {
    @Override
    public void preFreeze(Context context) throws IOException {
        // todo
    }
}
import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.StreamRequestHandler;
import com.aliyun.fc.runtime.PreStopHandler;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class PreStopSleepStreamNormal implements StreamRequestHandler, PreStopHandler {
    public PreStopSleepStreamNormal() {}

    @Override
    public void preStop(Context context) throws IOException {
        // todo
    }

    @Override
    public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
        // todo
    }
}